Created
November 20, 2017 07:44
-
-
Save lendeuel/ca7485a7d9e551ccf5a621acf1ae7522 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package global; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Scanner; | |
| import java.awt.AWTException; | |
| import java.awt.GraphicsEnvironment; | |
| import java.awt.HeadlessException; | |
| import java.awt.Rectangle; | |
| import java.awt.Robot; | |
| import java.awt.Toolkit; | |
| import java.awt.image.BufferedImage; | |
| import java.awt.peer.RobotPeer; | |
| import java.io.*; | |
| import javax.imageio.ImageIO; | |
| import com.philips.lighting.hue.listener.PHLightListener; | |
| import com.philips.lighting.hue.sdk.*; | |
| import com.philips.lighting.hue.sdk.utilities.PHUtilities; | |
| import com.philips.lighting.model.PHBridge; | |
| import com.philips.lighting.model.PHBridgeResource; | |
| import com.philips.lighting.model.PHHueError; | |
| import com.philips.lighting.model.PHHueParsingError; | |
| import com.philips.lighting.model.PHLight; | |
| import com.philips.lighting.model.PHLight.PHLightAlertMode; | |
| import com.philips.lighting.model.PHLight.PHLightColorMode; | |
| import com.philips.lighting.model.PHLight.PHLightEffectMode; | |
| import com.philips.lighting.model.PHLightState; | |
| public class HueThread extends Thread implements PHSDKListener | |
| { | |
| public boolean exit; | |
| public PHHueSDK ph; | |
| public void run() | |
| { | |
| ph = PHHueSDK.getInstance(); | |
| ph.setAppName("Command Line Hue Controller"); | |
| ph.setDeviceName("Command Line"); | |
| ph.getNotificationManager().registerSDKListener(this); | |
| Scanner s = new Scanner(System.in); | |
| while(!exit) | |
| { | |
| System.out.print("hue command: "); | |
| String[] splitArguements = s.nextLine().split(" "); | |
| takeCommand(splitArguements); | |
| } | |
| s.close(); | |
| } | |
| public void takeCommand(String[] arguements) | |
| { | |
| try | |
| { | |
| switch(arguements[0].toLowerCase()) | |
| { | |
| case "connect": | |
| connect(); | |
| break; | |
| case "reset": | |
| resetConnectionInfo(); | |
| break; | |
| case "help": | |
| System.out.println("connect - start a connection"); | |
| System.out.println("reset - reset connection info"); | |
| System.out.println("quit - exit program"); | |
| case "set": | |
| set(arguements); | |
| break; | |
| case "colorloop": | |
| colorloop(); | |
| break; | |
| case "capture": | |
| screenCapture(false, arguements[1], arguements[2]); | |
| break; | |
| case "capturedone": | |
| screenCapture(true, arguements[1], arguements[2]); | |
| break; | |
| case "killcapture": | |
| killCapture(); | |
| break; | |
| case "off": | |
| allOff(); | |
| break; | |
| case "quit": | |
| System.exit(0); | |
| break; | |
| } | |
| } | |
| catch(Exception e) | |
| { | |
| System.out.println("error"); | |
| } | |
| } | |
| public class PrimitiveConditionVariable | |
| { | |
| public boolean condition; | |
| public void waitOnCondition() | |
| { | |
| synchronized(this) | |
| { | |
| condition=false; | |
| while(!condition) | |
| { | |
| try | |
| { | |
| wait(0); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| } | |
| } | |
| } | |
| } | |
| public void setAndNotifyAll() | |
| { | |
| synchronized(this) | |
| { | |
| condition=true; | |
| notifyAll(); | |
| } | |
| } | |
| } | |
| public void resetConnectionInfo() | |
| { | |
| awaitingPushlink.setAndNotifyAll(); | |
| connecting.setAndNotifyAll(); | |
| ph.destroySDK(); | |
| ph = PHHueSDK.getInstance(); | |
| ph.setAppName("Command Line Hue Controller"); | |
| ph.setDeviceName("Command Line"); | |
| ph.getNotificationManager().registerSDKListener(this); | |
| } | |
| public PrimitiveConditionVariable connecting=new PrimitiveConditionVariable(); | |
| public boolean newConnection = false; | |
| private final String filename = "connectioninfo.txt"; | |
| public void saveConnection(String ip, String username) | |
| { | |
| File f = new File(filename); | |
| try | |
| { | |
| FileWriter w = new FileWriter(f); | |
| w.write(ip+"\n"+username+"\n"); | |
| w.close(); | |
| } | |
| catch (IOException e) | |
| { | |
| System.out.println("Could not save connection"); | |
| } | |
| } | |
| public void connect() throws FileNotFoundException, InterruptedException | |
| { | |
| File f = new File(filename); | |
| if(f.isFile()) | |
| { | |
| Scanner s = new Scanner(f); | |
| PHAccessPoint access = new PHAccessPoint(); | |
| access.setIpAddress(s.nextLine()); | |
| access.setUsername(s.nextLine()); | |
| System.out.println("Connecting.."); | |
| ph.connect(access); | |
| s.close(); | |
| } | |
| else | |
| { | |
| newConnection=true; | |
| System.out.println("Searching for bridge..."); | |
| ((PHBridgeSearchManager) ph.getSDKService(PHHueSDK.SEARCH_BRIDGE)).search(true, true); | |
| } | |
| connecting.waitOnCondition(); | |
| } | |
| public void allOff() | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setOn(false); | |
| ph.getSelectedBridge().setLightStateForDefaultGroup(state); | |
| System.out.println("Off."); | |
| } | |
| public void colorloop() | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setOn(true); | |
| state.setEffectMode(PHLightEffectMode.EFFECT_COLORLOOP); | |
| ph.getSelectedBridge().setLightStateForDefaultGroup(state); | |
| System.out.println("Colorloop."); | |
| } | |
| public void set(String[] arguements) | |
| { | |
| if(arguements.length<3) | |
| { | |
| System.out.println("Need to provide identifier and hue"); | |
| return; | |
| } | |
| if(arguements.length==3) | |
| { | |
| set(arguements[1], Integer.parseInt(arguements[2])); | |
| } | |
| if(arguements.length==4) | |
| { | |
| set(arguements[1], Float.parseFloat(arguements[2]), Float.parseFloat(arguements[3])); | |
| } | |
| } | |
| public void set(String identifier, int hue) | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setColorMode(PHLightColorMode.COLORMODE_HUE_SATURATION); | |
| state.setHue(hue); | |
| state.setBrightness(254); | |
| state.setSaturation(254); | |
| state.setOn(true); | |
| state.setEffectMode(PHLightEffectMode.EFFECT_NONE); | |
| state.setAlertMode(PHLightAlertMode.ALERT_NONE); | |
| set(identifier, state); | |
| } | |
| public void clear() | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setColorMode(PHLightColorMode.COLORMODE_XY); | |
| state.setOn(true); | |
| state.setEffectMode(PHLightEffectMode.EFFECT_NONE); | |
| state.setAlertMode(PHLightAlertMode.ALERT_NONE); | |
| state.setTransitionTime(0); | |
| set("all", state); | |
| } | |
| public void set(String identifier, float x, float y) | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setColorMode(PHLightColorMode.COLORMODE_XY); | |
| state.setX(x); | |
| state.setY(y); | |
| state.setOn(true); | |
| //state.setEffectMode(PHLightEffectMode.EFFECT_NONE); | |
| //state.setAlertMode(PHLightAlertMode.ALERT_NONE); | |
| state.setTransitionTime(0); | |
| set(identifier, state); | |
| } | |
| public void set(String identifier, PHLightState state) | |
| { | |
| if(identifier.equals("all")) | |
| { | |
| ph.getSelectedBridge().setLightStateForDefaultGroup(state); | |
| } | |
| else | |
| { | |
| final PrimitiveConditionVariable awaitState = new PrimitiveConditionVariable(); | |
| PHLightListener listener = new PHLightListener() | |
| { | |
| @Override | |
| public void onError(int code, String message) | |
| { | |
| //System.out.println("Error: Code: " + code + "Message: " + message); | |
| awaitState.setAndNotifyAll(); | |
| } | |
| @Override | |
| public void onStateUpdate(Map<String, String> successAttribute, List<PHHueError> errorAttribute) | |
| { | |
| } | |
| @Override | |
| public void onSuccess() | |
| { | |
| awaitState.setAndNotifyAll(); | |
| } | |
| @Override | |
| public void onReceivingLightDetails(PHLight light) | |
| { | |
| } | |
| @Override | |
| public void onReceivingLights(List<PHBridgeResource> lights) | |
| { | |
| } | |
| @Override | |
| public void onSearchComplete() | |
| { | |
| } | |
| }; | |
| ph.getSelectedBridge().updateLightState(identifier, state, listener); | |
| if(!awaitState.condition) | |
| { | |
| //awaitState.waitOnCondition(); | |
| } | |
| } | |
| } | |
| public void captureSet(String identifier, float x, float y) | |
| { | |
| PHLightState state = new PHLightState(); | |
| state.setColorMode(PHLightColorMode.COLORMODE_XY); | |
| state.setX(x); | |
| state.setY(y); | |
| int transitionTime = 1000/targetFPS/20; | |
| //transitionTime=0; | |
| state.setTransitionTime(transitionTime); | |
| set(identifier, state); | |
| } | |
| ScreenCaptureThread captureThread; | |
| public void screenCapture(boolean wait, String left, String right) | |
| { | |
| captureThread = new ScreenCaptureThread(new ToolkitScreenAccessor(), left, right); | |
| System.out.println("Started screen capture routine."); | |
| clear(); | |
| captureThread.start(); | |
| if(wait) | |
| { | |
| try | |
| { | |
| captureThread.join(); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| } | |
| } | |
| } | |
| public void killCapture() | |
| { | |
| System.out.println("Killing..."); | |
| captureThread.interrupt(); | |
| try | |
| { | |
| captureThread.join(); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| e.printStackTrace(); | |
| } | |
| System.out.println("Killed."); | |
| } | |
| public interface ScreenAccessor | |
| { | |
| public Rectangle getScreensize(); | |
| public int[] getRGBPixels(Rectangle selection); | |
| } | |
| public class ToolkitScreenAccessor implements ScreenAccessor | |
| { | |
| Toolkit toolkit; | |
| Rectangle screenRect; | |
| RobotPeer peer; | |
| public ToolkitScreenAccessor() | |
| { | |
| toolkit = Toolkit.getDefaultToolkit(); | |
| screenRect = new Rectangle(toolkit.getScreenSize()); | |
| try | |
| { | |
| peer = ((sun.awt.ComponentFactory) toolkit).createRobot(null, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()); | |
| } | |
| catch (HeadlessException | AWTException e) | |
| { | |
| // TODO Auto-generated catch block | |
| e.printStackTrace(); | |
| } | |
| } | |
| @Override | |
| public Rectangle getScreensize() | |
| { | |
| return screenRect; | |
| } | |
| @Override | |
| public int[] getRGBPixels(Rectangle selection) | |
| { | |
| return peer.getRGBPixels(selection); | |
| } | |
| } | |
| final int samplesPerFrame = 10000; | |
| final int targetFPS = 15; | |
| //describe the granularity to distinguish color changes | |
| final double granularity=0.05; | |
| //describe the portion of the color gamut you want | |
| final double relevantWidth = 0.6; | |
| final double relevantHeight = 0.6; | |
| //option to offset the calculated color values | |
| final double yoffset = 0; | |
| final double xoffset = .1; | |
| //ignore grayscale values where RGB are all this close to the average 0-255 | |
| final double grayscaleThreshold = 20; | |
| public class ScreenCaptureThread extends Thread | |
| { | |
| String leftLightId; | |
| String rightLightId; | |
| ScreenAccessor screenAccessor; | |
| //takes light ids | |
| public ScreenCaptureThread(ScreenAccessor screenAccessor, String left, String right) | |
| { | |
| this.screenAccessor = screenAccessor; | |
| leftLightId = left; | |
| rightLightId = right; | |
| } | |
| public void run() | |
| { | |
| int numWidths = (int) (relevantWidth/granularity)+1; | |
| int numHeights = (int) (relevantHeight/granularity)+1; | |
| int[][] counts = new int[numWidths][numHeights]; | |
| float[][] sumx = new float[numWidths][numHeights]; | |
| float[][] sumy = new float[numWidths][numHeights]; | |
| long targetTime = 1000/targetFPS; | |
| String model = ph.getSelectedBridge().getResourceCache().getLights().get(leftLightId).getModelNumber(); | |
| Rectangle screenRect = screenAccessor.getScreensize(); | |
| int pixelJumpPerFrame = (screenRect.width*screenRect.height)/samplesPerFrame; | |
| while(!isInterrupted()) | |
| { | |
| long startTime = System.currentTimeMillis(); | |
| int[] pixels = screenAccessor.getRGBPixels(screenRect); | |
| long captureTime = System.currentTimeMillis()-startTime; | |
| //clear the counts | |
| for(int i=0; i<numWidths; i++) | |
| { | |
| for(int j=0; j<numHeights; j++) | |
| { | |
| counts[i][j]=0; | |
| sumx[i][j]=0; | |
| sumy[i][j]=0; | |
| } | |
| } | |
| int maxCountX = 0; | |
| int maxCountY = 0; | |
| int maxCount = 0; | |
| for(int i=0; i<samplesPerFrame; i++) | |
| { | |
| int rgb = pixels[i*pixelJumpPerFrame]; | |
| int r = (rgb>>16)&0xff; | |
| int g = (rgb>>8)&0xff; | |
| int b = rgb&0xff; | |
| //check it isn't grayscale | |
| int average = (r+g+b)/3; | |
| if(Math.abs(average-r)<grayscaleThreshold && Math.abs(average-g)<grayscaleThreshold && Math.abs(average-b)<grayscaleThreshold) | |
| { | |
| continue; | |
| } | |
| float[] xy = PHUtilities.calculateXYFromRGB(r,g,b,model); | |
| int graphx = (int)((xy[0]-xoffset)/granularity); | |
| int graphy = (int)((xy[1]-yoffset)/granularity); | |
| counts[graphx][graphy]++; | |
| sumx[graphx][graphy]+=xy[0]; | |
| sumy[graphx][graphy]+=xy[1]; | |
| if(counts[graphx][graphy]>maxCount) | |
| { | |
| maxCountX=graphx; | |
| maxCountY=graphy; | |
| maxCount = counts[graphx][graphy]; | |
| } | |
| } | |
| //take the average of the highest frequency subdivision of the gamut | |
| float x = sumx[maxCountX][maxCountY]/maxCount; | |
| float y = sumy[maxCountX][maxCountY]/maxCount; | |
| //System.out.println("(" + x+","+y+")"); | |
| captureSet(leftLightId, x, y); | |
| captureSet(rightLightId, x, y); | |
| if(System.currentTimeMillis()-startTime>targetTime) | |
| { | |
| System.out.println("Not reaching fps goal"); | |
| System.out.println("Capture Time " + (captureTime)); | |
| System.out.println("Run Time " + (System.currentTimeMillis()-startTime)); | |
| } | |
| else | |
| { | |
| try | |
| { | |
| sleep(targetTime-(System.currentTimeMillis()-startTime)); | |
| } | |
| catch(Exception e) | |
| { | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /*Main Listener Code*/ | |
| @Override | |
| public void onAccessPointsFound(List<PHAccessPoint> accessPoints) | |
| { | |
| PHAccessPoint selection = accessPoints.get(0); | |
| System.out.println("Connecting..."); | |
| ph.connect(selection); | |
| } | |
| public PrimitiveConditionVariable awaitingPushlink = new PrimitiveConditionVariable(); | |
| @Override | |
| public void onAuthenticationRequired(PHAccessPoint accessPoint) | |
| { | |
| AuthenticationThread t = new AuthenticationThread(); | |
| ph.startPushlinkAuthentication(accessPoint); | |
| t.start(); | |
| } | |
| public class AuthenticationThread extends Thread | |
| { | |
| public void run() | |
| { | |
| System.out.println("Pushlink required please push."); | |
| int time = 30; | |
| awaitingPushlink.condition=false; | |
| synchronized(awaitingPushlink) | |
| { | |
| while(!awaitingPushlink.condition && time>0) | |
| { | |
| System.out.println("Awaiting Push "+time+" seconds remaining"); | |
| try | |
| { | |
| awaitingPushlink.wait(1000); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| time++; | |
| } | |
| time--; | |
| } | |
| if(time==0) | |
| { | |
| System.out.println("Timed out pushlink, please begin connection again."); | |
| awaitingPushlink.setAndNotifyAll(); | |
| connecting.setAndNotifyAll(); | |
| } | |
| } | |
| } | |
| } | |
| @Override | |
| public void onBridgeConnected(PHBridge bridge, String username) | |
| { | |
| System.out.println("Connection successful"); | |
| ph.setSelectedBridge(bridge); | |
| //PHHeartbeatManager beat = PHHeartbeatManager.getInstance(); | |
| //beat.enableLightsHeartbeat(bridge, PHHueSDK.HB_INTERVAL); | |
| if(newConnection) | |
| { | |
| newConnection=false; | |
| saveConnection(bridge.getResourceCache().getBridgeConfiguration().getIpAddress(), username); | |
| } | |
| awaitingPushlink.setAndNotifyAll(); | |
| connecting.setAndNotifyAll(); | |
| } | |
| @Override | |
| public void onCacheUpdated(List<Integer> cacheNotifications, PHBridge bridge) | |
| { | |
| // TODO Auto-generated method stub | |
| } | |
| @Override | |
| public void onConnectionLost(PHAccessPoint access) | |
| { | |
| System.out.println("Connection lost please connect again."); | |
| resetConnectionInfo(); | |
| } | |
| @Override | |
| public void onConnectionResumed(PHBridge bridge) | |
| { | |
| // TODO Auto-generated method stub | |
| } | |
| ArrayList<Integer> ignoredCodes; | |
| @Override | |
| public void onError(int code, String message) | |
| { | |
| if(ignoredCodes == null) | |
| { | |
| ignoredCodes = new ArrayList<Integer>(); | |
| ignoredCodes.add(101); | |
| } | |
| if(!ignoredCodes.contains(code)) | |
| { | |
| System.out.println("Error, please connect again:\n"+message); | |
| resetConnectionInfo(); | |
| } | |
| } | |
| @Override | |
| public void onParsingErrors(List<PHHueParsingError> parsingErrors) | |
| { | |
| System.out.println("Error found, please connect again."); | |
| resetConnectionInfo(); | |
| } | |
| /*End Main Listener Code*/ | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment