package zutil.osal.linux.app; import zutil.Timer; import zutil.log.LogUtil; import java.io.*; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Provides a java interface for the linux service "upsd" from the * The NUT (Network UPS Tools) package. * * Created by Ziver on 2016-04-01. */ public class NutUPSClient { private static final Logger logger = LogUtil.getLogger(); public static final String DEFAULT_HOST = "localhost"; public static final int DEFAULT_PORT = 3493; public static final int POLL_INTERVAL = 2000; private static final Pattern keyValuePattern = Pattern.compile("\\W*:\\W*"); private static final String PARAMETER_MANUFACTURER = "ups.mfr"; private static final String PARAMETER_MODEL = "ups.model"; private static final String PARAMETER_DESCRIPTION = "ups.description"; private static final String PARAMETER_POWER_LOAD = "ups.load"; //ups.power private static final String PARAMETER_POWER_USAGE = "ups.realpower"; //ups.power private static final String PARAMETER_BATTERY_CHARGE = "battery.charge"; private static final String PARAMETER_BATTERY_VOLTAGE = "battery.voltage"; private static final String PARAMETER_POLL_INTERVAL = "driver.parameter.pollinterval"; private String host; private int port; private ArrayList upsDevices; private Timer pollTimer; public NutUPSClient(String host, int port){ this.upsDevices = new ArrayList<>(); this.host = host; this.port = port; this.pollTimer = new Timer(POLL_INTERVAL); } public UPSDevice getUPS(String id){ update(); return __getUPS(id); } private UPSDevice __getUPS(String id){ for (UPSDevice ups : upsDevices){ if (ups.equals(id)) return ups; } return null; } public UPSDevice[] getUPSList(){ update(); return upsDevices.toArray(new UPSDevice[0]); } protected synchronized void update(){ if(pollTimer.hasTimedOut()){ logger.fine("Starting UPS data refresh ("+host+":"+port+")"); try(Socket s = new Socket(host, port)) { Writer out = new OutputStreamWriter(s.getOutputStream()); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); // Refresh device list HashMap tmp = new HashMap<>(); sendListCommand(out, in, "UPS", tmp); for (String upsId : tmp.keySet()){ if(__getUPS(upsId) == null) { logger.fine("Registering new UPS device: "+upsId); upsDevices.add(new UPSDevice(upsId)); } } // Refresh device data for (UPSDevice ups : upsDevices){ ups.update(out, in); } } catch (Exception e){ logger.log(Level.WARNING, null, e); } // reset timer pollTimer.start(); } } /** * Reference http://networkupstools.org/docs/developer-guide.chunked/ar01s09.html */ private void sendListCommand(Writer out, BufferedReader in, String cmd, HashMap parameters) throws IOException { String request = "LIST " + cmd; out.write(request + "\n"); out.flush(); String line = in.readLine(); if ( ! line.startsWith("BEGIN LIST")) throw new IOException("Unexpected response from upsd: Request: '"+request+"' Response: '"+line+"'"); Pattern listKeyValuePatter = Pattern.compile("\\w* (?:\\w* )?([\\w.]+) \"(.*)\""); while ((line=in.readLine()) != null){ if (line.startsWith("END")) break; Matcher m = listKeyValuePatter.matcher(line); m.matches(); parameters.put( m.group(1), m.group(2)); } } public class UPSDevice{ private String id; private HashMap parameters = new HashMap<>(); protected UPSDevice(String id){ this.id = id; } protected synchronized void update(Writer out, BufferedReader in) throws IOException { if(pollTimer == null || pollTimer.hasTimedOut()){ parameters.clear(); logger.fine("Updating UPS parameters for: "+id); sendListCommand(out, in, "VAR "+id, parameters); } } public boolean equals(Object o){ if (o instanceof String) return id.equals(o); else if (o instanceof UPSDevice) return id.equals(((UPSDevice) o).id); return false; } public String getId(){ return id; } public String getModelName(){ return parameters.get(PARAMETER_MANUFACTURER) + " " + parameters.get(PARAMETER_MODEL); } public String getDescription() { return parameters.get(PARAMETER_DESCRIPTION); } public int getPowerLoad(){ return Integer.parseInt(parameters.get(PARAMETER_POWER_LOAD)); } public int getPowerUsage(){ return Integer.parseInt(parameters.get(PARAMETER_POWER_USAGE)); } public int getBatteryCharge(){ return Integer.parseInt(parameters.get(PARAMETER_BATTERY_CHARGE)); } public double getBatteryVoltage(){ return Double.parseDouble(parameters.get(PARAMETER_BATTERY_VOLTAGE)); } } }