-
-
Save stephenlb/518b8312393d43c23336791105c4ac6f to your computer and use it in GitHub Desktop.
[Blog] DIY Hue Lightbulb with Android Control
This file contains 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
#!/usr/bin/python | |
import time | |
import RPi.GPIO as GPIO | |
from pubnub.pnconfiguration import PNConfiguration | |
from pubnub.pubnub import PubNub |
This file contains 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
## Make your pin assignments | |
red_gpio = 18 | |
green_gpio = 23 | |
blue_gpio = 24 |
This file contains 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
## Setup GPIO Board and Pins | |
GPIO.setmode(GPIO.BCM) # BCM for GPIO numbering | |
GPIO.setup(red_gpio, GPIO.OUT) | |
GPIO.setup(green_gpio, GPIO.OUT) | |
GPIO.setup(blue_gpio, GPIO.OUT) |
This file contains 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
## Init the GPIO PWMs | |
Freq = 100 #Hz | |
RED = GPIO.PWM(red_gpio, Freq) | |
RED.start(0) | |
GREEN = GPIO.PWM(green_gpio, Freq) | |
GREEN.start(0) | |
BLUE = GPIO.PWM(blue_gpio, Freq) | |
BLUE.start(0) |
This file contains 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
# Update the hue with R G B values | |
def updateHue(R, G, B): | |
rVal = 100 - (R/255.0)*100 # Will have to change these values depending on | |
gVal = 100 - (G/255.0)*100 # whether your LED has a common cathode or common | |
bVal = 100 - (B/255.0)*100 # anode. This code is for common anode. | |
print "rgb(%.2f, %.2f, %.2f)" % (rVal, gVal, bVal) | |
RED.ChangeDutyCycle(rVal) | |
GREEN.ChangeDutyCycle(gVal) | |
BLUE.ChangeDutyCycle(bVal) |
This file contains 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
rVal = (R/255.0)*100 # Common Cathode (Ground) | |
rVal = 100 - (R/255.0)*100 # Common Anode (5V) |
This file contains 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
def rgb(): | |
updateHue(255,0,0); time.sleep(2) | |
updateHue(0,255,0); time.sleep(2) | |
updateHue(0,0,255); time.sleep(2) |
This file contains 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
def main(): | |
rgb() | |
updateHue(0,0,0); # Light off | |
main() |
This file contains 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
def main(): | |
... | |
# Instantiate Pubnub | |
pnconfig = PNConfiguration() | |
pnconfig.subscribe_key = "my_subkey" | |
pnconfig.publish_key = "my_pubkey" | |
pnconfig.ssl = False | |
pubnub = PubNub(pnconfig) | |
# This is the channel your Pi will be listening on for RGB values | |
channel = 'phue' | |
# This callback handles any messages received on subscribed channel | |
def _callback(msg, n): | |
print(msg) | |
updateHue(msg["RED"], msg["GREEN"], msg["BLUE"]) | |
def _error(m): | |
print(m) | |
class MySubscribeCallback(SubscribeCallback): | |
def presence(self, pubnub, presence): | |
pass # handle incoming presence data | |
def status(self, pubnub, status): | |
if status.category == PNStatusCategory.PNUnexpectedDisconnectCategory: | |
pass # This event happens when radio / connectivity is lost | |
elif status.category == PNStatusCategory.PNConnectedCategory: | |
# Connect event. You can do stuff like publish, and know you'll get it. | |
# Or just use the connected event to confirm you are subscribed for | |
# UI / internal notifications, etc | |
pubnub.publish().channel("awesomeChannel").message("hello!!").async(my_publish_callback) | |
elif status.category == PNStatusCategory.PNReconnectedCategory: | |
pass | |
# Happens as part of our regular operation. This event happens when | |
# radio / connectivity is lost, then regained. | |
elif status.category == PNStatusCategory.PNDecryptionErrorCategory: | |
pass | |
# Handle message decryption error. Probably client configured to | |
# encrypt messages and on live data feed it received plain text. | |
def message(self, pubnub, message): | |
print(message) | |
updateHue(message["RED"], message["GREEN"], message["BLUE"]) | |
pubnub.subscribe().channels(channel).execute() | |
pubnub.add_listener(MySubscribeCallback()) |
This file contains 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
dependencies { | |
compile fileTree(dir: 'libs', include: ['*.jar']) | |
compile group: 'com.pubnub', name: 'pubnub-gson', version: '4.14.0' | |
} |
This file contains 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 me.kevingleason.phue; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.LinearLayout; | |
import android.widget.SeekBar; | |
import android.widget.TextView; | |
import com.pubnub.api.Callback; | |
import com.pubnub.api.Pubnub; | |
import com.pubnub.api.PubnubError; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
public class MainActivity extends Activity { | |
public static final int COLOR_RED = 0; // Arbitrary ID's | |
public static final int COLOR_BLUE = 1; // that are used | |
public static final int COLOR_GREEN = 2; // later in the code | |
SeekBar mRedSeek, mGreenSeek, mBlueSeek; // All our layout pieces | |
LinearLayout mRGBValueHolder; // that we will be editing | |
// Pubnub instance and all the keys you will need to stream data | |
private Pubnub mPubNub; | |
public static final String PUBLISH_KEY = "your-pub-key"; | |
public static final String SUBSCRIBE_KEY = "your-sub-key"; | |
public static final String CHANNEL = "phue"; | |
private long lastUpdate = System.currentTimeMillis(); // Used to thereshold | |
... | |
} |
This file contains 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
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
// Instantiate PubNub. We will cover this shortly. | |
initPubNub(); | |
// Get Seek Bars. They will be at R.id.<your-seekbar-id> | |
mRedSeek = (SeekBar) findViewById(R.id.red_seek); | |
mGreenSeek = (SeekBar) findViewById(R.id.green_seek); | |
mBlueSeek = (SeekBar) findViewById(R.id.blue_seek); | |
mRGBValueHolder = (LinearLayout) findViewById(R.id.rgb_value_holder); | |
// Setup Seek Bars. We will cover this function shortly. | |
setupSeekBar(mRedSeek, COLOR_RED); | |
setupSeekBar(mGreenSeek, COLOR_GREEN); | |
setupSeekBar(mBlueSeek, COLOR_BLUE); | |
} |
This file contains 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
public void initPubNub(){ | |
PNConfiguration pnConfiguration = new PNConfiguration(); | |
pnConfiguration.setSubscribeKey("demo"); | |
pnConfiguration.setPublishKey("demo"); | |
this.mPubNub = new PubNub(pnConfiguration); | |
this.mPubNub.setUUID("AndroidPHue"); | |
subscribe(); | |
} |
This file contains 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
public void subscribe(){ | |
try { | |
this.mPubNub.subscribe() | |
.channels(CHANNEL) // subscribe to channels | |
.withPresence() // also subscribe to related presence information | |
.execute(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} |
This file contains 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
public void setupSeekBar(SeekBar seekBar, final int colorID){ | |
seekBar.setMax(255); // Seek bar values goes 0-255 | |
seekBar.setProgress(255); // Set the knob to 255 to start | |
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { | |
@Override | |
public void onStopTrackingTouch(SeekBar seekBar) { | |
publish(mRedSeek.getProgress(), mGreenSeek.getProgress(), mBlueSeek.getProgress()); | |
} | |
@Override | |
public void onStartTrackingTouch(SeekBar seekBar) { | |
publish(mRedSeek.getProgress(), mGreenSeek.getProgress(), mBlueSeek.getProgress()); | |
} | |
@Override | |
public void onProgressChanged(SeekBar seekBar, int progress, | |
boolean fromUser) { | |
TextView colorValueText; | |
switch (colorID){ // Get the TextView identified by the colorID | |
case COLOR_RED: | |
colorValueText = (TextView)findViewById(R.id.red_value); | |
break; | |
case COLOR_GREEN: | |
colorValueText = (TextView) findViewById(R.id.green_value); | |
break; | |
case COLOR_BLUE: | |
colorValueText = (TextView)findViewById(R.id.blue_value); | |
break; | |
default: | |
Log.e("SetupSeek","Invalid color."); | |
return; | |
} | |
colorValueText.setText(String.valueOf(progress)); // Update the 0-255 text | |
int red = mRedSeek.getProgress(); // Get Red value 0-255 | |
int green = mGreenSeek.getProgress(); // Get Grn value 0-255 | |
int blue = mBlueSeek.getProgress(); // Get Blu value 0-255 | |
updateRGBViewHolderColor(red, green, blue); // Change the background of the viewholder | |
long now = System.currentTimeMillis(); // Only allow 1 pub every 100 milliseconds | |
if (now - lastUpdate > 100 && fromUser) { // Threshold and only send when user sliding | |
lastUpdate = now; | |
publish(red, green, blue); // Stream RGB values to the Pi | |
} | |
} | |
}); | |
} |
This file contains 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
private void updateRGBViewHolderColor(int red, int green, int blue){ | |
int alpha = 255; // No opacity | |
int color = (alpha << 24) | (red << 16) | (green << 8) | blue; | |
mRGBValueHolder.setBackgroundColor(color); | |
} |
This file contains 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
public void publish(int red, int green, int blue){ | |
JSONObject js = new JSONObject(); | |
try { | |
js.put("RED", red); | |
js.put("GREEN", green); | |
js.put("BLUE", blue); | |
} catch (JSONException e) { e.printStackTrace(); } | |
pubnub.publish().channel(CHANNEL).message(js).async(new PNCallback<PNPublishResult>() { | |
@Override | |
public void onResponse(PNPublishResult result, PNStatus status) { | |
// Check whether request successfully completed or not. | |
if (!status.isError()) { | |
Log.d("PUBNUB" result.toString()); | |
} | |
// Request processing failed. | |
else { | |
// Handle message publish error. Check 'category' property to find out possible issue | |
// because of which request did fail. | |
// | |
// Request can be resent using: [status retry]; | |
} | |
} | |
}); | |
} |
This file contains 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
public void setRGBSeeks(int red, int green, int blue){ | |
mRedSeek.setProgress(red); | |
mGreenSeek.setProgress(green); | |
mBlueSeek.setProgress(blue); | |
} |
This file contains 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
public void lightOff(View view){ | |
publish(0, 0, 0); // 0,0,0 is black or OFF | |
setRGBSeeks(0, 0, 0); | |
} | |
public void lightOn(View view){ | |
publish(255, 255, 255); // 255,255,255 is White or ON | |
setRGBSeeks(255, 255, 255); | |
} |
This file contains 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
public void initPubNub(){ | |
PNConfiguration pnConfiguration = new PNConfiguration(); | |
pnConfiguration.setSubscribeKey("SubscribeKey"); | |
pnConfiguration.setPublishKey("PublishKey"); | |
pnConfiguration.setSecure(false); | |
this.mPubNub = new PubNub(pnConfiguration); | |
this.mPubNub.setUUID("AndroidPHue"); | |
hereNow(); // Check if any light is on the channel before you join | |
subscribe(); | |
} |
This file contains 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
public void hereNow(){ | |
this.mPubNub.hereNow() | |
// tailor the next two lines to example | |
.channels(CHANNEL) | |
.includeUUIDs(true) | |
.async(new PNCallback<PNHereNowResult>() { | |
@Override | |
public void onResponse(PNHereNowResult result, PNStatus status) { | |
if (status.isError()) { | |
// handle error | |
return; | |
} | |
Log.d("PUBNUB", response.toString()); | |
try { | |
JSONObject json = (JSONObject) result; | |
if (json.getInt("occupancy") == 0){ | |
setRGBSeeks(0,0,0); | |
MainActivity.this.runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
Toast.makeText(MainActivity.this,"No Light Detected.", Toast.LENGTH_LONG).show(); | |
// Do something to views... | |
} | |
}); | |
} | |
} catch (JSONException e){ e.printStackTrace(); } | |
} | |
}); | |
} |
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="me.kevingleason.phue" > | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | |
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> | |
... | |
</manifest> |
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<!-- colors.xml --> | |
<resources> | |
<color name="red">#FFFF0000</color> | |
<color name="green">#00FF00</color> | |
<color name="blue">#0000FF</color> | |
</resources> |
This file contains 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
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:context=".MainActivity" | |
android:orientation="vertical"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="72dp"> | |
<Button | |
android:onClick="lightOn" | |
style="@style/AppTheme.Button" | |
android:text="@string/on_button"/> | |
<ImageButton | |
android:src="@drawable/phue" | |
android:scaleType="centerCrop" | |
style="@style/AppTheme.Button"/> | |
<Button | |
android:onClick="lightOff" | |
style="@style/AppTheme.Button" | |
android:text="@string/off_button"/> | |
</LinearLayout> | |
<SeekBar | |
android:id="@+id/red_seek" | |
style="@style/AppTheme.SeekBar" | |
android:background="@color/red" /> | |
<SeekBar | |
android:id="@+id/green_seek" | |
style="@style/AppTheme.SeekBar" | |
android:background="@color/green" /> | |
<SeekBar | |
android:id="@+id/blue_seek" | |
style="@style/AppTheme.SeekBar" | |
android:background="@color/blue" /> | |
<LinearLayout | |
android:id="@+id/rgb_value_holder" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<TextView | |
android:id="@+id/red_value" | |
android:textColor="@color/red" | |
android:text="255" | |
style="@style/AppTheme.RGB"/> | |
<TextView | |
android:id="@+id/green_value" | |
android:textColor="@color/green" | |
android:text="255" | |
style="@style/AppTheme.RGB"/> | |
<TextView | |
android:id="@+id/blue_value" | |
android:textColor="@color/blue" | |
android:text="255" | |
style="@style/AppTheme.RGB"/> | |
</LinearLayout> | |
</LinearLayout> |
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<!-- main/res/values/strings.xml --> | |
<resources> | |
<string name="app_name">PHue</string> | |
<string name="hello_world">Hello world!</string> | |
<string name="action_settings">Settings</string> | |
<string name="on_button">ON</string> | |
<string name="off_button">OFF</string> | |
</resources> |
This file contains 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
<resources> | |
<!-- main/res/values/styles.xml --> | |
<!-- Base application theme. --> | |
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> | |
<!-- Customize your theme here. --> | |
</style> | |
<!-- This is the container or RGB values --> | |
<style name="AppTheme.RGB"> | |
<item name="android:layout_width">0dp</item> | |
<item name="android:layout_height">match_parent</item> | |
<item name="android:layout_weight">1</item> | |
<item name="android:gravity">center</item> | |
<item name="android:textSize">40sp</item> | |
<item name="android:textStyle">bold</item> | |
</style> | |
<!-- The seek bar slider styles --> | |
<style name="AppTheme.SeekBar"> | |
<item name="android:layout_width">match_parent</item> | |
<item name="android:layout_height">wrap_content</item> | |
<item name="android:padding">25dp</item> | |
</style> | |
<!-- The on and off button styles --> | |
<style name="AppTheme.Button"> | |
<item name="android:layout_width">0dp</item> | |
<item name="android:layout_height">match_parent</item> | |
<item name="android:layout_weight">1</item> | |
<item name="android:background">#000</item> | |
<item name="android:textSize">20sp</item> | |
<item name="android:textColor">#fff</item> | |
</style> | |
</resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment