Skip to content

Instantly share code, notes, and snippets.

@lendeuel
Created November 20, 2017 07:44
Show Gist options
  • Select an option

  • Save lendeuel/ca7485a7d9e551ccf5a621acf1ae7522 to your computer and use it in GitHub Desktop.

Select an option

Save lendeuel/ca7485a7d9e551ccf5a621acf1ae7522 to your computer and use it in GitHub Desktop.
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