import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import javax.imageio.ImageIO; /** * web temperature setter * * @author matecsaba */ public class temper implements Runnable { /** * this is needed for cli startup * * @param args command line parameters */ public static void main(String[] args) { temper app = new temper(); String a; try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); a = "" + app.getClass().getName() + "."; a = temper.httpRequest("http://localhost/" + a, "./" + a, "cli", "clibrowser", "user", args, buf); a = "type=" + a + "\r\ndata:\r\n" + buf.toString(); } catch (Exception e) { a = "exception " + e.getMessage(); } System.out.println(a); } /** * where i'm located in ram */ protected static temper staticTemper = null; /** * do one request * * @param url url of app * @param path path of app * @param peer client address * @param agent user agent * @param user auth data * @param par parameters * @param buf result buffer, if empty, pathname must present * @return [pathname"][file name.]extension * @throws Exception if something went wrong */ public static String httpRequest(String url, String path, String peer, String agent, String user, String[] par, ByteArrayOutputStream buf) throws Exception { if (staticTemper == null) { staticTemper = new temper(); staticTemper.path = path.substring(0, path.lastIndexOf(".")); staticTemper.url = new URI(url).toURL().getPath(); staticTemper.doInit(); new Thread(staticTemper).start(); } if (staticTemper.doRequest(par, buf, peer) == 2) { return "png"; } else { return "html"; } } /** * where i'm located on host */ protected String path; /** * where i'm located on net */ protected String url; /** * reading store */ protected temperData measDat[] = new temperData[0]; /** * allowed peers */ protected String allowIp; /** * inside reading used */ protected int measIn = -1; /** * outside reading used */ protected int measOut = -1; /** * current value sent */ protected int currValue = 0x10000; /** * last needed temperature */ protected float lastNeeded = 20; /** * time needed temperature */ protected long timeNeeded = 0; /** * time heating temperature */ protected long timeHeating = 0; /** * time zone to use */ protected String tzdata = "Z"; /** * http refresh seconds */ protected int refreshSeconds = 3; /** * log file */ protected String logFile = "temper.log"; /** * script file */ protected String scrFile = "temper.sh"; /** * window min time */ protected int windowTim = 15 * 60 * 1000; /** * measure timeout */ protected int measTime = 5 * 60 * 1000; /** * measure timeout */ protected int measIotm = 5 * 1000; /** * measure interval */ protected int collTime = 30 * 1000; /** * measure history */ protected int collHist = 90; /** * measure discard */ protected Float collIlde = 0.2F; /** * temperature minimum */ protected float tempMin = 10; /** * temperature maximum */ protected float tempMax = 30; /** * heat tolerance */ protected float heatTol = 0.3F; /** * cool tolerance */ protected float coolTol = 0.3F; /** * cool tolerance */ protected float ventTol = 0.1F; /** * window tolerance */ protected float windowTol = -0.9F; /** * heat pin */ protected int heatPin = 0x0; /** * cool pin */ protected int coolPin = 0x0; /** * vent pin */ protected int ventPin = 0x0; /** * relay pin */ protected int relayPin = 0x0; /** * door pin */ protected int doorPin = 0x0; /** * door time */ protected int doorTime = 1000; /** * door codes */ protected List doorCode = new ArrayList(); /** * door log */ protected List doorLog = new ArrayList(); /** * door temporary codes allowed */ protected boolean doorTemp = false; /** * door max */ protected int doorMax = 5; /** * door count */ protected int doorCnt = 0; /** * last setter peer */ protected String lastSetter = "nobody"; private synchronized void setValue(int val) { val &= (heatPin | coolPin | ventPin | doorPin | relayPin); if (currValue == val) { return; } try { Runtime rtm = Runtime.getRuntime(); String[] cmd = new String[2]; cmd[0] = scrFile; cmd[1] = val + ""; Process prc = rtm.exec(cmd); prc.waitFor(); } catch (Exception e) { return; } int mask = heatPin | coolPin | ventPin; if ((currValue & mask) != (val & mask)) { timeHeating = temperUtil.getTime(); for (int i = 0; i < measDat.length; i++) { measDat[i].setWindow(); } } currValue = val; } private void rangeCheck() { if (lastNeeded > tempMax) { lastNeeded = tempMax; } if (lastNeeded < tempMin) { lastNeeded = tempMin; } } private int doCalc() { for (int i = 0; i < measDat.length; i++) { measDat[i].getValue(); measDat[i].doCalc(); } measIn = -1; measOut = -1; int prioIn = -1; int prioOut = -1; boolean win = false; for (int i = 0; i < measDat.length; i++) { if (!measDat[i].isWorking) { continue; } if (measDat[i].myPri < 0) { continue; } if (measDat[i].inside) { if (prioIn > measDat[i].myPri) { continue; } measIn = i; prioIn = measDat[i].myPri; } else { if (prioOut > measDat[i].myPri) { continue; } measOut = i; prioOut = measDat[i].myPri; } win |= measDat[i].isWindow; } int i = currValue & ~(heatPin | coolPin | ventPin); if (win) { return i; } if (measIn < 0) { return i; } temperData.results res = measDat[measIn].lastCalc; if ((ventPin != 0) && (measOut >= 0)) { boolean maybe = (currValue & ventPin) != 0; float diff = measDat[measIn].lastMeasure - measDat[measOut].lastMeasure; if (diff < 0) { diff = -diff; } maybe &= diff < ventTol; boolean good; switch (res) { case cool: good = measDat[measIn].lastMeasure > (measDat[measOut].lastMeasure + coolTol); break; case heat: good = measDat[measIn].lastMeasure < (measDat[measOut].lastMeasure - heatTol); break; default: return i; } //good &= (res == measDat[measOut].histRes) || (measDat[measOut].histRes == temperData.results.idle); if (good || maybe) { return i | ventPin; } } switch (res) { case cool: return i | coolPin; case heat: return i | heatPin; default: return i; } } private synchronized void writeLog(String who) { if (who == null) { who = lastSetter; } String a = ""; for (int i = 0; i < measDat.length; i++) { a = a + ";" + measDat[i].getLog(); } temperUtil.append(logFile, temperUtil.getTime() + ";" + who + ";" + currValue + ";" + lastNeeded + ";" + measIn + ";" + measOut + a); } /** * initialize */ public void doInit() { readConfig(); timeNeeded = temperUtil.getTime(); timeHeating = timeNeeded; lastSetter = "boot"; rangeCheck(); writeLog(""); } public void run() { for (;;) { rangeCheck(); setValue(doCalc()); writeLog(null); temperUtil.sleep(collTime); } } private void readConfig() { logFile = path + ".log"; List c = temperUtil.readup(path + ".cfg"); if (c == null) { return; } List m = new ArrayList(); for (int i = 0; i < c.size(); i++) { String s = c.get(i); int o = s.indexOf("="); if (o < 0) { continue; } String a = s.substring(0, o).trim().toLowerCase(); s = s.substring(o + 1, s.length()).trim(); if (a.equals("script")) { scrFile = s; continue; } if (a.equals("needed")) { lastNeeded = temperUtil.str2num(s); continue; } if (a.equals("tzdata")) { tzdata = s; continue; } if (a.equals("door-count")) { doorMax = (int) temperUtil.str2num(s); continue; } if (a.equals("door-code")) { doorCode.add(new temperCode(doorCode.size() + 1, s, false)); continue; } if (a.equals("door-tcode")) { doorCode.add(new temperCode(doorCode.size() + 1, s, true)); continue; } if (a.equals("door-temp")) { doorTemp = s.equals("on"); continue; } if (a.equals("door-time")) { doorTime = (int) temperUtil.str2num(s); continue; } if (a.equals("door-pin")) { doorPin = (int) temperUtil.str2num(s); continue; } if (a.equals("log-file")) { logFile = s; continue; } if (a.equals("temp-min")) { tempMin = temperUtil.str2num(s); continue; } if (a.equals("temp-max")) { tempMax = temperUtil.str2num(s); continue; } if (a.equals("heat-tol")) { heatTol = temperUtil.str2num(s); continue; } if (a.equals("heat-pin")) { heatPin = (int) temperUtil.str2num(s); continue; } if (a.equals("cool-tol")) { coolTol = temperUtil.str2num(s); continue; } if (a.equals("cool-pin")) { coolPin = (int) temperUtil.str2num(s); continue; } if (a.equals("vent-tol")) { ventTol = temperUtil.str2num(s); continue; } if (a.equals("vent-pin")) { ventPin = (int) temperUtil.str2num(s); continue; } if (a.equals("win-tim")) { windowTim = (int) (temperUtil.str2num(s) * 60 * 1000); continue; } if (a.equals("win-tol")) { windowTol = temperUtil.str2num(s); continue; } if (a.equals("collect")) { collTime = (int) (temperUtil.str2num(s) * 1000); continue; } if (a.equals("history")) { collHist = (int) temperUtil.str2num(s); continue; } if (a.equals("idling")) { collIlde = temperUtil.str2num(s); continue; } if (a.equals("timeout")) { measTime = (int) (temperUtil.str2num(s) * 60 * 1000); continue; } if (a.equals("relay-pin")) { relayPin = (int) temperUtil.str2num(s); continue; } if (a.equals("refresh-delay")) { refreshSeconds = (int) temperUtil.str2num(s); continue; } if (a.equals("allowed-ip")) { allowIp = s; continue; } if (a.equals("measure")) { m.add(s); continue; } } measDat = new temperData[m.size()]; for (int i = 0; i < measDat.length; i++) { measDat[i] = new temperData(this, i + 1, m.get(i)); } } protected void drawRightAlighed(Graphics2D g2d, int mx10, int y, String s) { FontMetrics fm = g2d.getFontMetrics(); g2d.drawString(s, mx10 - fm.stringWidth(s), y); } protected void putStart(ByteArrayOutputStream buf, String tit, String res) throws Exception { buf.write("".getBytes()); buf.write("".getBytes()); buf.write(tit.getBytes()); buf.write("".getBytes()); buf.write(res.getBytes()); buf.write("".getBytes()); } private temperCode findCode(String s) { for (int i = 0; i < doorCode.size(); i++) { temperCode cur = doorCode.get(i); if (!s.equals(cur.code)) { continue; } return cur; } return null; } private BufferedImage drawHist(List hst, int dot) { float tmpMin = Float.MAX_VALUE; float tmpMax = Float.MIN_VALUE; for (int o = 0; o < hst.size(); o++) { temperHist l = hst.get(o); tmpMin = Float.min(tmpMin, l.need); tmpMax = Float.max(tmpMax, l.need); for (int i = 0; i < l.meas.length; i++) { float v = l.meas[i]; tmpMin = Float.min(tmpMin, v); tmpMax = Float.max(tmpMax, v); } } tmpMax -= tmpMin; final int mx = 1800; final int my = 900; final int mx10 = mx - 10; final int mx20 = mx - 20; final int my1 = my - 1; final int my10 = my - 10; final int my20 = my - 20; final int my30 = my - 30; final int my40 = my - 40; final int my50 = my - 50; BufferedImage img = new BufferedImage(mx, my, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = img.createGraphics(); g2d.setBackground(Color.gray); g2d.setFont(new Font("Serif", Font.BOLD, 20)); g2d.setPaint(Color.gray); g2d.fillRect(0, 0, img.getWidth(), img.getHeight()); g2d.setPaint(Color.black); Color colors[] = { Color.green, Color.red, Color.cyan, Color.magenta, Color.orange, Color.pink, Color.yellow, Color.white, Color.blue,}; for (int o = 0; o < hst.size(); o++) { temperHist l = hst.get(o); int x = ((o * mx20) / hst.size()) + 10; g2d.setPaint(Color.black); g2d.drawRect(x, my10 - (int) (((l.need - tmpMin) * my20) / tmpMax), dot, dot); if (l.curr != 0) { g2d.drawRect(x, 10, dot, dot); } for (int i = 0; i < l.meas.length; i++) { g2d.setPaint(colors[i]); g2d.drawRect(x, my10 - (int) (((l.meas[i] - tmpMin) * my20) / tmpMax), dot, dot); } } for (int i = 0; i < measDat.length; i++) { g2d.setPaint(colors[i]); drawRightAlighed(g2d, mx10, my50 - (i * 20), measDat[i].myNam); } g2d.setPaint(Color.black); drawRightAlighed(g2d, mx10, my30, "needed"); for (int i = 20; i < my20; i += 50) { float v = (float) i * tmpMax; v = v / (float) my20; v += tmpMin; String a = v + " "; g2d.drawString(a.substring(0, 6), 1, my10 - i); } String a; if ((hst.get(hst.size() - 1).time - hst.get(0).time) < (86400 * 3000)) { a = "HH:mm"; } else { a = "MMMdd"; } for (int i = 0; i < mx20; i += 100) { temperHist l = hst.get((i * hst.size()) / mx20); DateFormat dat = new SimpleDateFormat(a, Locale.US); g2d.drawString(dat.format(new Date((long) l.time)), i + 10, my1); } return img; } private boolean checkPeer(ByteArrayOutputStream buf, String peer) throws Exception { if (allowIp == null) { return false; } if (allowIp.indexOf(";" + peer + ";") >= 0) { return false; } putStart(buf, "restricted", "you are not allowed"); return true; } /** * do one request * * @param par parameters * @param buf buffer to use * @param peer address * @return 1 on html result * @throws Exception on error */ public synchronized int doRequest(String[] par, ByteArrayOutputStream buf, String peer) throws Exception { String tmp = ""; String cmd = ""; for (int i = 0; i < par.length; i++) { String a = par[i]; int o = a.indexOf("="); if (o < 1) { continue; } String b = a.substring(0, o); a = a.substring(o + 1, a.length()); if (b.equals("temp")) { tmp = a; } if (b.equals("cmd")) { cmd = a; } } if (cmd.equals("heat")) { if (checkPeer(buf, peer)) { return 1; } lastNeeded = temperUtil.str2num(tmp); timeNeeded = temperUtil.getTime(); lastSetter = peer; rangeCheck(); } if (cmd.equals("relayor")) { int i = ((int) temperUtil.str2num(tmp)) & relayPin; tmp = "" + (currValue | i); cmd = "relayset"; } if (cmd.equals("relayand")) { int i = ((int) temperUtil.str2num(tmp)) & relayPin; tmp = "" + (currValue & i); cmd = "relayset"; } if (cmd.equals("relayxor")) { int i = ((int) temperUtil.str2num(tmp)) & relayPin; tmp = "" + (currValue ^ i); cmd = "relayset"; } if (cmd.equals("relayset")) { if (checkPeer(buf, peer)) { return 1; } if (relayPin == 0) { putStart(buf, "relay", "relay not set"); return 1; } int i = ((int) temperUtil.str2num(tmp)) & relayPin; setValue((currValue & (~relayPin)) | i); writeLog(peer); putStart(buf, "relay", "relay set to " + i + " from range " + relayPin); return 1; } if (cmd.equals("guests")) { if (checkPeer(buf, peer)) { return 1; } temperCode res = findCode(tmp); if (res == null) { putStart(buf, "door", "invalid code"); return 1; } if (res.temp) { putStart(buf, "door", "disabled code"); return 1; } doorTemp = true; putStart(buf, "door", "guests enabled"); return 1; } if (cmd.equals("closed")) { if (checkPeer(buf, peer)) { return 1; } temperCode res = findCode(tmp); if (res == null) { putStart(buf, "door", "invalid code"); return 1; } if (res.temp) { putStart(buf, "door", "disabled code"); return 1; } doorTemp = false; putStart(buf, "door", "guests disabled"); return 1; } if (cmd.equals("door")) { if (checkPeer(buf, peer)) { return 1; } temperCode res = findCode(tmp); if (res == null) { putStart(buf, "door", "invalid code"); return 1; } if (res.temp && (!doorTemp)) { putStart(buf, "door", "disabled code"); return 1; } setValue(currValue | doorPin); writeLog(peer); temperUtil.sleep(doorTime); setValue(currValue & (~doorPin)); writeLog(peer); doorLog.add(new temperLog(this, peer, res.myNum)); for (;;) { if (doorLog.size() <= doorMax) { break; } doorLog.remove(0); } doorCnt++; putStart(buf, "door", "door opened"); return 1; } if (cmd.equals("history")) { temperData cur = measDat[(int) temperUtil.str2num(tmp) - 1]; ImageIO.write(drawHist(cur.histDat, 10), "png", buf); return 2; } if (!cmd.equals("graph")) { rangeCheck(); String a = "temper"; buf.write(a.getBytes()); a = ""; buf.write(a.getBytes()); long tim = temperUtil.getTime(); a = ""; buf.write(a.getBytes()); for (int i = 0; i < measDat.length; i++) { a = measDat[i].getMeas(); buf.write(a.getBytes()); } a = "
numnamevaluelasterrreadworkwinreshstwtmpwtim

"; buf.write(a.getBytes()); a = "tolerance: heat " + heatTol + ", cool " + coolTol + ", vent " + ventTol + ", window " + windowTol + ", time " + temperUtil.timePast(windowTim, 0) + "
"; buf.write(a.getBytes()); a = "needed: " + lastNeeded + " celsius, since " + temperUtil.time2str(tzdata, timeNeeded) + ", " + temperUtil.timePast(tim, timeNeeded) + " ago by " + lastSetter + "
"; buf.write(a.getBytes()); a = "doing: " + currValue + ", since " + temperUtil.time2str(tzdata, timeHeating) + ", " + temperUtil.timePast(tim, timeHeating) + " ago, using #" + (measIn + 1) + "/#" + (measOut + 1) + " for " + temperUtil.timePast(measTime, 0) + "
"; buf.write(a.getBytes()); a = "
wish: celsius (" + tempMin + "-" + tempMax + ")"; buf.write(a.getBytes()); buf.write("".getBytes()); buf.write("".getBytes()); buf.write("

".getBytes()); for (int i = -3; i <= 3; i++) { int o = i + (int) lastNeeded; a = "((" + o + ".0))"; buf.write(a.getBytes()); a = "((" + o + ".5))"; buf.write(a.getBytes()); } a = "

the door was opened " + doorCnt + " times:
"; buf.write(a.getBytes()); a = ""; buf.write(a.getBytes()); for (int i = doorLog.size() - 1; i >= 0; i--) { a = doorLog.get(i).getMeas(i, tim); buf.write(a.getBytes()); } a = "
numwhenagocodepeer

"; buf.write(a.getBytes()); buf.write("".getBytes()); return 1; } File fi = new File(logFile); FileReader fr = new FileReader(fi); fr.skip(fi.length() - (long) (temperUtil.str2num(tmp) * 64000)); BufferedReader f = new BufferedReader(fr); f.readLine(); List history = new ArrayList(); while (f.ready()) { String s = f.readLine(); temperHist l = new temperHist(); l.parseLine(s); history.add(l); } f.close(); ImageIO.write(drawHist(history, 1), "png", buf); return 2; } }