Skip to content

Commit

Permalink
Merge pull request #14 from mariusmotea/develop
Browse files Browse the repository at this point in the history
two-way light sync + minor improvements
  • Loading branch information
mariusmotea authored Jun 20, 2017
2 parents 09d33ed + 4052c45 commit 2ac1a6b
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 265 deletions.
49 changes: 36 additions & 13 deletions BridgeEmulator/HueEmulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,14 @@ def rules_processor(scheduler=False):
for action in bridge_config["rules"][rule]["actions"]:
Thread(target=sendRequest, args=["/api/" + bridge_config["rules"][rule]["owner"] + action["address"], action["method"], json.dumps(action["body"])]).start()

def sendRequest(url, method, data):
def sendRequest(url, method, data, time_out=3):
if not url.startswith( 'http://' ):
url = "http://127.0.0.1" + url
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(url, data=data)
request.add_header("Content-Type",'application/json')
request.get_method = lambda: method
response = opener.open(request, timeout=3).read()
response = opener.open(request, timeout=time_out).read()
return response

def convert_xy(x, y, bri): #needed for milight hub that don't work with xy values
Expand Down Expand Up @@ -246,7 +246,7 @@ def sendLightRequest(light, data):
else:
url += "&" + key + "=" + str(value)
elif lights_address[light]["protocol"] == "hue": #Original Hue light
url = "http://" + lights_address[light]["ip"] + "/api/" + lights_address[light]["username"] + "/lights/" + lights_address[light]["light_id"] + "/state";
url = "http://" + lights_address[light]["ip"] + "/api/" + lights_address[light]["username"] + "/lights/" + lights_address[light]["light_id"] + "/state"
method = 'PUT'
payload = data
elif lights_address[light]["protocol"] == "milight": #MiLight bulb
Expand Down Expand Up @@ -358,9 +358,21 @@ def scan_for_lights(): #scan for ESP8266 lights and strips
except Exception, e:
print(ip + " is unknow device " + str(e))

def syncWithTradfri(): #update Hue Bridge lights states from Ikea Tradfri gateway
def syncWithLights(): #update Hue Bridge lights states
for light in lights_address:
if lights_address[light]["protocol"] == "ikea_tradfri":
if lights_address[light]["protocol"] == "native":
try:
light_data = json.loads(sendRequest("http://" + lights_address[light]["ip"] + "/get?light=" + str(lights_address[light]["light_nr"]), "GET", "{}", 0.5))
except:
bridge_config["lights"][light]["state"]["reachable"] = False
print("request error")
else:
bridge_config["lights"][light]["state"]["reachable"] = True
bridge_config["lights"][light]["state"].update(light_data)
elif lights_address[light]["protocol"] == "hue":
light_data = json.loads(sendRequest("http://" + lights_address[light]["ip"] + "/api/" + lights_address[light]["username"] + "/lights/" + lights_address[light]["light_id"] + "/state"), "GET", "{}", 1))
bridge_config["lights"][light]["state"].update(light_data)
elif lights_address[light]["protocol"] == "ikea_tradfri":
light_stats = json.loads(check_output("./coap-client-linux -m get -u \"Client_identity\" -k \"" + lights_address[light]["security_code"] + "\" \"coaps://" + lights_address[light]["ip"] + ":5684/15001/" + str(lights_address[light]["device_id"]) +"\"", shell=True).split("\n")[3])
bridge_config["lights"][light]["state"]["on"] = bool(light_stats["3311"][0]["5850"])
bridge_config["lights"][light]["state"]["bri"] = light_stats["3311"][0]["5851"]
Expand All @@ -371,7 +383,6 @@ def syncWithTradfri(): #update Hue Bridge lights states from Ikea Tradfri gatewa
elif light_stats["3311"][0]["5706"] == "efd275":
bridge_config["lights"][light]["state"]["ct"] = 470


def description():
return """<root xmlns=\"urn:schemas-upnp-org:device-1-0\">
<specVersion>
Expand Down Expand Up @@ -502,7 +513,11 @@ def update_all_lights():
payload = {}
payload["on"] = bridge_config["lights"][light]["state"]["on"]
payload["bri"] = bridge_config["lights"][light]["state"]["bri"]
payload[bridge_config["lights"][light]["state"]["colormode"]] = bridge_config["lights"][light]["state"][bridge_config["lights"][light]["state"]["colormode"]]
if bridge_config["lights"][light]["state"]["colormode"] in ["xy", "ct"]:
payload[bridge_config["lights"][light]["state"]["colormode"]] = bridge_config["lights"][light]["state"][bridge_config["lights"][light]["state"]["colormode"]]
elif bridge_config["lights"][light]["state"]["colormode"] == "hs":
payload["hue"] = bridge_config["lights"][light]["state"]["hue"]
payload["sat"] = bridge_config["lights"][light]["state"]["sat"]
Thread(target=sendLightRequest, args=[light, payload]).start()
sleep(0.5)
print("update status for light " + light)
Expand All @@ -518,7 +533,7 @@ def do_GET(self):
if self.path == '/description.xml':
self.wfile.write(description())
elif self.path == '/favicon.ico':
self.send_response(404)
self.wfile.write("file not found")
elif self.path.startswith("/tradfri"): #setup Tradfri gateway
get_parameters = parse_qs(urlparse(self.path).query)
if "code" in get_parameters:
Expand Down Expand Up @@ -623,7 +638,7 @@ def do_GET(self):
self.wfile.write(json.dumps(bridge_config))
elif len(url_pices) == 4: #print specified object config
if url_pices[3] == "lights": #add changes from IKEA Tradfri gateway to bridge
syncWithTradfri()
syncWithLights()
self.wfile.write(json.dumps(bridge_config[url_pices[3]]))
elif len(url_pices) == 5:
if url_pices[4] == "new": #return new lights and sensors only
Expand Down Expand Up @@ -728,7 +743,13 @@ def do_PUT(self):
del bridge_config["scenes"][url_pices[4]]["lightstates"][light]["ct"]
elif "hue" in bridge_config["scenes"][url_pices[4]]["lightstates"][light]:
del bridge_config["scenes"][url_pices[4]]["lightstates"][light]["hue"]
bridge_config["scenes"][url_pices[4]]["lightstates"][light][bridge_config["lights"][light]["state"]["colormode"]] = bridge_config["lights"][light]["state"][bridge_config["lights"][light]["state"]["colormode"]]
del bridge_config["scenes"][url_pices[4]]["lightstates"][light]["sat"]
if bridge_config["lights"][light]["state"]["colormode"] in ["ct", "xy"]:
bridge_config["scenes"][url_pices[4]]["lightstates"][light][bridge_config["lights"][light]["state"]["colormode"]] = bridge_config["lights"][light]["state"][bridge_config["lights"][light]["state"]["colormode"]]
elif bridge_config["lights"][light]["state"]["colormode"] == "hs":
bridge_config["scenes"][url_pices[4]]["lightstates"][light]["hue"] = bridge_config["lights"][light]["state"]["hue"]
bridge_config["scenes"][url_pices[4]]["lightstates"][light]["sat"] = bridge_config["lights"][light]["state"]["sat"]

if url_pices[3] == "sensors":
for key, value in put_dictionary.iteritems():
bridge_config[url_pices[3]][url_pices[4]][key].update(value)
Expand All @@ -744,8 +765,8 @@ def do_PUT(self):
bridge_config["lights"][light]["state"]["colormode"] = "xy"
elif "ct" in bridge_config["scenes"][put_dictionary["scene"]]["lightstates"][light]:
bridge_config["lights"][light]["state"]["colormode"] = "ct"
elif "hue" in bridge_config["scenes"][put_dictionary["scene"]]["lightstates"][light]:
bridge_config["lights"][light]["state"]["colormode"] = "hue"
elif "hue" or "sat" in bridge_config["scenes"][put_dictionary["scene"]]["lightstates"][light]:
bridge_config["lights"][light]["state"]["colormode"] = "hs"
Thread(target=sendLightRequest, args=[light, bridge_config["scenes"][put_dictionary["scene"]]["lightstates"][light]]).start()
update_group_stats(light)
elif "bri_inc" in put_dictionary:
Expand Down Expand Up @@ -779,8 +800,10 @@ def do_PUT(self):
elif url_pices[3] == "lights": #state is applied to a light
Thread(target=sendLightRequest, args=[url_pices[4], put_dictionary]).start()
for key in put_dictionary.iterkeys():
if key in ["ct", "xy", "hue"]: #colormode must be set by bridge
if key in ["ct", "xy"]: #colormode must be set by bridge
bridge_config["lights"][url_pices[4]]["state"]["colormode"] = key
elif key in ["hue", "sat"]:
bridge_config["lights"][url_pices[4]]["state"]["colormode"] = "hs"
update_group_stats(url_pices[4])
if not url_pices[4] == "0": #group 0 is virtual, must not be saved in bridge configuration
try:
Expand Down
Binary file added Images/hue-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 40 additions & 28 deletions Lights/Arduino/GenericWifiHueLight/GenericWifiHueLight.ino
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,29 @@ void apply_scene(uint8_t new_scene) {
}
}

void lightEngine() {
for (uint8_t color = 0; color < pwm_channels; color++) {
if (light_state) {
if (rgbw[color] != current_rgbw[color] ) {
in_transition = true;
current_rgbw[color] += step_level[color];
if ((step_level[color] > 0.0f && current_rgbw[color] > rgbw[color]) || (step_level[color] < 0.0f && current_rgbw[color] < rgbw[color])) current_rgbw[color] = rgbw[color];
analogWrite(pins[color], (int)(current_rgbw[color] * 4));
}
} else {
if (current_rgbw[color] != 0) {
in_transition = true;
current_rgbw[color] -= step_level[color];
if (current_rgbw[color] < 0.0f) current_rgbw[color] = 0;
analogWrite(pins[color], (int)(current_rgbw[color] * 4));
}
}
}
if (in_transition) {
delay(6);
in_transition = false;
}
}

void setup() {
EEPROM.begin(512);
Expand All @@ -226,8 +249,6 @@ void setup() {
pins[1] = green_pin;
pins[2] = blue_pin;
pins[3] = white_pin;
WiFiManager wifiManager;
wifiManager.autoConnect("New Hue Light");
analogWriteRange(1024);
analogWriteFreq(4096);

Expand All @@ -238,7 +259,13 @@ void setup() {

if (EEPROM.read(1) == 1 || (EEPROM.read(1) == 0 && EEPROM.read(0) == 1)) {
light_state = true;
} else {
for (uint8_t i = 0; i < 200; i++) {
lightEngine();
}
}
WiFiManager wifiManager;
wifiManager.autoConnect("New Hue Light");
if (! light_state) {
while (WiFi.status() != WL_CONNECTED) {
analogWrite(pins[0], 10);
delay(250);
Expand Down Expand Up @@ -413,7 +440,16 @@ void setup() {
});

server.on("/get", []() {
server.send(200, "text/plain", "{\"R\":" + (String)rgbw[0] + ", \"G\": " + (String)rgbw[1] + ", \"B\":" + (String)rgbw[2] + ", \"W\":" + (String)rgbw[3] + ", \"bri\":" + (String)bri + ", \"xy\": [" + (String)x + "," + (String)y + "], \"ct\":" + (String)ct + ", \"sat\": " + (String)sat + ", \"hue\": " + (String)hue + ", \"colormode\":" + color_mode + "}");
String colormode;
String power_status;
power_status = light_state ? "true" : "false";
if (color_mode == 1)
colormode = "xy";
else if (color_mode == 2)
colormode = "ct";
else if (color_mode == 3)
colormode = "hs";
server.send(200, "text/plain", "{\"on\": " + power_status + ", \"bri\": " + (String)bri + ", \"xy\": [" + (String)x + ", " + (String)y + "], \"ct\":" + (String)ct + ", \"sat\": " + (String)sat + ", \"hue\": " + (String)hue + ", \"colormode\": \"" + colormode + "\"}");
});

server.on("/detect", []() {
Expand Down Expand Up @@ -582,30 +618,6 @@ void setup() {
server.begin();
}

void lightEngine() {
for (uint8_t color = 0; color < pwm_channels; color++) {
if (light_state) {
if (rgbw[color] != current_rgbw[color] ) {
in_transition = true;
current_rgbw[color] += step_level[color];
if ((step_level[color] > 0.0f && current_rgbw[color] > rgbw[color]) || (step_level[color] < 0.0f && current_rgbw[color] < rgbw[color])) current_rgbw[color] = rgbw[color];
analogWrite(pins[color], (int)(current_rgbw[color] * 4));
}
} else {
if (current_rgbw[color] != 0) {
in_transition = true;
current_rgbw[color] -= step_level[color];
if (current_rgbw[color] < 0.0f) current_rgbw[color] = 0;
analogWrite(pins[color], (int)(current_rgbw[color] * 4));
}
}
}
if (in_transition) {
delay(6);
in_transition = false;
}
}

void loop() {
ArduinoOTA.handle();
server.handleClient();
Expand Down
100 changes: 54 additions & 46 deletions Lights/Arduino/SK6812HueStrip/SK6812HueStrip.ino
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,47 @@ void apply_scene(uint8_t new_scene, uint8_t light) {
}
}

void lightEngine() {
for (int i = 0; i < lightsCount; i++) {
if (light_state[i]) {
if (rgbw[i][0] != current_rgbw[i][0] || rgbw[i][1] != current_rgbw[i][1] || rgbw[i][2] != current_rgbw[i][2] || rgbw[i][3] != current_rgbw[i][3]) {
in_transition = true;
for (uint8_t k = 0; k <= 3; k++) {
if (rgbw[i][k] != current_rgbw[i][k]) current_rgbw[i][k] += step_level[i][k];
if ((step_level[i][k] > 0.0 && current_rgbw[i][k] > rgbw[i][k]) || (step_level[i][k] < 0.0 && current_rgbw[i][k] < rgbw[i][k])) current_rgbw[i][k] = rgbw[i][k];
}
for (int j = 0; j < pixelCount / lightsCount ; j++)
{
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_rgbw[i][0], (int)current_rgbw[i][1], (int)current_rgbw[i][2], (int)current_rgbw[i][3]));
}
strip.Show();
}
} else {
if (current_rgbw[i][0] != 0 || current_rgbw[i][1] != 0 || current_rgbw[i][2] != 0 || current_rgbw[i][3] != 0) {
in_transition = true;
for (uint8_t k = 0; k <= 3; k++) {
if (current_rgbw[i][k] != 0) current_rgbw[i][k] -= step_level[i][k];
if (current_rgbw[i][k] < 0) current_rgbw[i][k] = 0;
}
for (int j = 0; j < pixelCount / lightsCount ; j++)
{
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_rgbw[i][0], (int)current_rgbw[i][1], (int)current_rgbw[i][2], (int)current_rgbw[i][3]));
}
strip.Show();
}
}
}
if (in_transition) {
delay(6);
in_transition = false;
}
}

void setup() {
strip.Begin();
strip.Show();
EEPROM.begin(512);

WiFiManager wifiManager;
wifiManager.autoConnect("New Hue Light");

//WiFi.config(strip_ip, gateway_ip, subnet_mask);

for (uint8_t light = 0; light < lightsCount; light++) {
Expand All @@ -256,7 +288,13 @@ void setup() {
for (int i = 0; i < lightsCount; i++) {
light_state[i] = true;
}
} else {
for (int j = 0; j < 200; j++) {
lightEngine();
}
WiFiManager wifiManager;
wifiManager.autoConnect("New Hue Light");
}
if (! light_state[0]) {
infoLight(white);
while (WiFi.status() != WL_CONNECTED) {
infoLight(red);
Expand Down Expand Up @@ -436,12 +474,18 @@ void setup() {

server.on("/get", []() {
uint8_t light;
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "light") {
light = server.arg(i).toInt() - 1;
}
}
server.send(200, "text/plain", "{\"R\":" + (String)current_rgbw[light][0] + ", \"G\": " + (String)current_rgbw[light][1] + ", \"B\":" + (String)current_rgbw[light][2] + ", \"W\":" + (String)current_rgbw[light][3] + ", \"bri\":" + (String)bri[light] + ", \"xy\": [" + (String)x[light] + "," + (String)y[light] + "], \"ct\":" + (String)ct[light] + ", \"sat\": " + (String)sat[light] + ", \"hue\": " + (String)hue[light] + ", \"colormode\":" + color_mode[light] + "}");
if (server.hasArg("light"))
light = server.arg("light").toInt() - 1;
String colormode;
String power_status;
power_status = light_state[light] ? "true" : "false";
if (color_mode[light] == 1)
colormode = "xy";
else if (color_mode[light] == 2)
colormode = "ct";
else if (color_mode[light] == 3)
colormode = "hs";
server.send(200, "text/plain", "{\"on\": " + power_status + ", \"bri\": " + (String)bri[light] + ", \"xy\": [" + (String)x[light] + ", " + (String)y[light] + "], \"ct\":" + (String)ct[light] + ", \"sat\": " + (String)sat[light] + ", \"hue\": " + (String)hue[light] + ", \"colormode\": \"" + colormode + "\"}");
});

server.on("/detect", []() {
Expand Down Expand Up @@ -611,42 +655,6 @@ void setup() {
server.begin();
}

void lightEngine() {
for (int i = 0; i < lightsCount; i++) {
if (light_state[i]) {
if (rgbw[i][0] != current_rgbw[i][0] || rgbw[i][1] != current_rgbw[i][1] || rgbw[i][2] != current_rgbw[i][2] || rgbw[i][3] != current_rgbw[i][3]) {
in_transition = true;
for (uint8_t k = 0; k <= 3; k++) {
if (rgbw[i][k] != current_rgbw[i][k]) current_rgbw[i][k] += step_level[i][k];
if ((step_level[i][k] > 0.0 && current_rgbw[i][k] > rgbw[i][k]) || (step_level[i][k] < 0.0 && current_rgbw[i][k] < rgbw[i][k])) current_rgbw[i][k] = rgbw[i][k];
}
for (int j = 0; j < pixelCount / lightsCount ; j++)
{
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_rgbw[i][0], (int)current_rgbw[i][1], (int)current_rgbw[i][2], (int)current_rgbw[i][3]));
}
strip.Show();
}
} else {
if (current_rgbw[i][0] != 0 || current_rgbw[i][1] != 0 || current_rgbw[i][2] != 0 || current_rgbw[i][3] != 0) {
in_transition = true;
for (uint8_t k = 0; k <= 3; k++) {
if (current_rgbw[i][k] != 0) current_rgbw[i][k] -= step_level[i][k];
if (current_rgbw[i][k] < 0) current_rgbw[i][k] = 0;
}
for (int j = 0; j < pixelCount / lightsCount ; j++)
{
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_rgbw[i][0], (int)current_rgbw[i][1], (int)current_rgbw[i][2], (int)current_rgbw[i][3]));
}
strip.Show();
}
}
}
if (in_transition) {
delay(6);
in_transition = false;
}
}

void loop() {
ArduinoOTA.handle();
server.handleClient();
Expand Down
Loading

0 comments on commit 2ac1a6b

Please sign in to comment.