package com.kuxhausen.huemore.net.lifx; import android.content.Context; import android.os.SystemClock; import com.kuxhausen.huemore.net.NetworkBulb; import com.kuxhausen.huemore.persistence.Utils; import com.kuxhausen.huemore.state.BulbState; import com.kuxhausen.huemore.utils.DeferredLog; import lifx.java.android.entities.LFXHSBKColor; import lifx.java.android.entities.LFXTypes; import lifx.java.android.light.LFXLight; public class LifxBulb implements NetworkBulb, LFXLight.LFXLightListener { //In milis private final static long TRANSMIT_TIMEOUT_TIME = 10000; LifxConnection mConnection; private Context mContext; private Long mBaseId; private String mName; private String mDeviceId; private ExtraData mExtraData; private LFXLight mLight; private long mInitializedTime; private BulbState mDesiredState; // In SystemClock.elapsedRealtime(); private Long mDesiredLastChanged; private Integer mMaxBri; public LifxBulb(Context c, Long bulbBaseId, String bulbName, String bulbDeviceId, ExtraData bulbData, LifxConnection lifxConnection) { mBaseId = bulbBaseId; mName = bulbName; mDeviceId = bulbDeviceId; mExtraData = bulbData; mContext = c; mConnection = lifxConnection; mDesiredState = new BulbState(); } protected void onInitialize() { mInitializedTime = SystemClock.elapsedRealtime(); } public void lightConnected(LFXLight light) { mLight = light; mLight.addLightListener(this); if (!mDesiredState.isEmpty()) { setState(mDesiredState); mDesiredState = new BulbState(); } } public void lightDisconnected() { if (mLight != null) { mLight.removeLightListener(this); } mLight = null; } @Override public ConnectivityState getConnectivityState() { if (mLight != null && mLight.getReachability() .equals(LFXTypes.LFXDeviceReachability.REACHABLE)) { return ConnectivityState.Connected; } else if (SystemClock.elapsedRealtime() > (mInitializedTime + this.TRANSMIT_TIMEOUT_TIME)) { return ConnectivityState.Unreachable; } return ConnectivityState.Unknown; } @Override public void setState(BulbState bs) { DeferredLog.d("lifx", "setState but mLight?null %b", (mLight == null)); mDesiredLastChanged = SystemClock.elapsedRealtime(); if (mLight != null && bs != null) { //TODO cache so don't have to guess when SDK dosn't know float lifxBrightness = .5f; float lifxHue = 0; float lifxSat = 0; int lifxCt = 3500; if (mLight.getColor() != null) { lifxBrightness = mLight.getColor().getBrightness(); lifxHue = mLight.getColor().getHue(); lifxSat = mLight.getColor().getSaturation(); lifxCt = mLight.getColor().getKelvin(); } if (bs.get255Bri() != null) { lifxBrightness = (bs.get255Bri() / 255f); } //clip brightness to ensure proper behavior (0 brightness not allowed) lifxBrightness = Math.max(.01f, lifxBrightness); if (bs.getOn() != null) { if (bs.getOn()) { mLight.setPowerState(LFXTypes.LFXPowerState.ON); } else { mLight.setPowerState(LFXTypes.LFXPowerState.OFF); } } //Send full color, color temp, or just brightness if (bs.hasXY() || bs.getKelvinCT() != null || bs.get255Bri() != null) { if (bs.hasXY()) { float[] hs = Utils.xyTOhs(bs.getXY()); lifxHue = 360 * hs[0]; lifxSat = hs[1]; LFXHSBKColor newColor = LFXHSBKColor.getColor(lifxHue, lifxSat, lifxBrightness, 3500); mLight.setColor(newColor); } else if (bs.getKelvinCT() != null) { lifxHue = 0; lifxSat = 0; lifxCt = bs.getKelvinCT(); LFXHSBKColor newColor = LFXHSBKColor.getColor(0, 0, lifxBrightness, lifxCt); mLight.setColor(newColor); } LFXHSBKColor newColor = LFXHSBKColor.getColor(lifxHue, lifxSat, lifxBrightness, lifxCt); if (bs.getTransitionTime() != null) { mLight.setColorOverDuration(newColor, bs.getTransitionTime() * 100); } else { mLight.setColor(newColor); } } } else { //cache for when light not connected yet mDesiredState.merge(bs); } //TODO move or limit to actual state changes this.mConnection.getDeviceManager().onStateChanged(); } protected boolean hasPendingWork() { if (mDesiredLastChanged != null && (mDesiredLastChanged + this.TRANSMIT_TIMEOUT_TIME) > SystemClock.elapsedRealtime()) { return true; } return false; } @Override public BulbState getState(GetStateConfidence confidence) { BulbState result = new BulbState(); switch (confidence) { case GUESS: BulbState guess = new BulbState(); guess.setPercentBri(50); guess.setOn(true); guess.setAlert(BulbState.Alert.NONE); guess.setEffect(BulbState.Effect.NONE); guess.setMiredCT(300); guess.setTransitionTime(BulbState.TRANSITION_TIME_DEFAULT); result = BulbState.merge(guess, result); case KNOWN: if (mLight != null && mLight.getColor() != null) { LFXHSBKColor color = mLight.getColor(); BulbState confirmed = new BulbState(); confirmed.setOn(mLight.getPowerState() == LFXTypes.LFXPowerState.ON); confirmed.setPercentBri((int) (color.getBrightness() * 100.0)); //TODO improve lifx color logic confirmed.setKelvinCT(color.getKelvin()); float[] hs = {color.getHue() / 360.0f, color.getSaturation()}; confirmed.setXY(Utils.hsTOxy(hs)); result = BulbState.merge(confirmed, result); } case DESIRED: result = BulbState.merge(mDesiredState, result); } return result; } @Override public String getName() { if (mLight != null) { return mLight.getLabel(); } return ""; } @Override public void rename(String name) { if (mLight != null) { mLight.setLabel(name); } } @Override public Long getBaseId() { return mBaseId; } @Override public void lightDidChangeLabel(LFXLight light, String label) { } @Override public void lightDidChangeColor(LFXLight light, LFXHSBKColor color) { } @Override public void lightDidChangePowerState(LFXLight light, LFXTypes.LFXPowerState powerState) { } public static class ExtraData { } }