diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..f617616
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,16 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ lint:
+
+ runs-on: ubuntu-latest
+
+ container:
+ image: valalang/lint
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Lint
+ run: io.elementary.vala-lint -d .
diff --git a/data/com.github.manexim.home.appdata.xml.in b/data/com.github.manexim.home.appdata.xml.in
index 1a0d482..d60b07a 100644
--- a/data/com.github.manexim.home.appdata.xml.in
+++ b/data/com.github.manexim.home.appdata.xml.in
@@ -21,6 +21,30 @@
com.github.manexim.home
+
+
+ New:
+
+ - Use color picker to set color of smart bulbs
+
+ Improved:
+
+ - Show an error page if network is not available
+
+ Fixed:
+
+ Translations:
+
+ - Russian (by camellan)
+ - French (by NathanBnm)
+ - German (by meisenzahl)
+ - Japanese (by ryonakano)
+ - Portuguese (by aimproxy)
+ - Polish (by oskarkunik)
+
+
+
New:
diff --git a/debian/changelog b/debian/changelog
index 1009c0b..aafc198 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+com.github.manexim.home (0.5.0) bionic; urgency=medium
+
+[NEW]
+ * Use color picker to set color of smart bulbs
+[IMPROVED]
+ * Show an error page if network is not available
+[FIXED]
+[TRANSLATIONS]
+ * Russian (by camellan)
+ * French (by NathanBnm)
+ * German (by meisenzahl)
+ * Japanese (by ryonakano)
+ * Portuguese (by aimproxy)
+ * Polish (by oskarkunik)
+
+ -- Marius Meisenzahl Sun, 03 Nov 2019 14:24:03 +0100
+
com.github.manexim.home (0.4.2) bionic; urgency=medium
[NEW]
diff --git a/src/Application.vala b/src/Application.vala
index e47987d..c2485cc 100644
--- a/src/Application.vala
+++ b/src/Application.vala
@@ -36,7 +36,9 @@ public class Application : Granite.Application {
var css_provider = new Gtk.CssProvider ();
css_provider.load_from_resource ("com/github/manexim/home/styles/application.css");
- Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+ Gtk.StyleContext.add_provider_for_screen (
+ Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+ );
}
public static int main (string[] args) {
diff --git a/src/colors/HSB.vala b/src/colors/HSB.vala
index 5b369f1..6b44e5b 100644
--- a/src/colors/HSB.vala
+++ b/src/colors/HSB.vala
@@ -19,4 +19,72 @@
* Authored by: Marius Meisenzahl
*/
-public class Colors.HSB {}
+public class Colors.HSB {
+ public uint16 hue;
+ public uint8 saturation;
+ public uint8 brightness;
+
+ public HSB () {}
+
+ public HSB.from_rgb (RGB rgb) {
+ double min, max, delta;
+ double h, s, b;
+
+ double red = rgb.red / 255.0;
+ double green = rgb.green / 255.0;
+ double blue = rgb.blue / 255.0;
+
+ min = red;
+ min = green < min ? green : min;
+ min = blue < min ? blue : min;
+
+ max = red;
+ max = green > max ? green : max;
+ max = blue > max ? blue : max;
+
+ b = max;
+ delta = max - min;
+
+ if (max != 0) {
+ s = delta / max;
+ } else {
+ s = 0;
+ h = 0;
+
+ hue = (uint16) (h + 0.5);
+ saturation = (uint8) (s * 100 + 0.5);
+ brightness = (uint8) (b * 100 + 0.5);
+
+ return;
+ }
+
+ if (max == min) {
+ h = 0;
+ s = 0;
+
+ hue = (uint16) (h + 0.5);
+ saturation = (uint8) (s * 100 + 0.5);
+ brightness = (uint8) (b * 100 + 0.5);
+
+ return;
+ }
+
+ if (red == max) {
+ h = (green - blue) / delta;
+ } else if (green == max) {
+ h = 2 + (blue - red) / delta;
+ } else {
+ h = 4 + (red - green) / delta;
+ }
+
+ h *= 60;
+
+ if (h < 0) {
+ h += 360;
+ }
+
+ hue = (uint16) (h + 0.5);
+ saturation = (uint8) (s * 100 + 0.5);
+ brightness = (uint8) (b * 100 + 0.5);
+ }
+}
diff --git a/src/colors/RGB.vala b/src/colors/RGB.vala
index 86bd2b7..d452df3 100644
--- a/src/colors/RGB.vala
+++ b/src/colors/RGB.vala
@@ -29,4 +29,75 @@ public class Colors.RGB {
public RGB.from_hex (string hex) {
hex.scanf ("%02x%02x%02x", &red, &green, &blue);
}
+
+ public RGB.from_hsb (HSB hsb) {
+ int i;
+ double f, p, q, t;
+ double r, g, b;
+
+ double hue, saturation, brightness;
+ hue = (double) hsb.hue;
+ saturation = (double) (hsb.saturation / 100.0);
+ brightness = (double) (hsb.brightness / 100.0);
+
+ if (saturation == 0) {
+ r = brightness;
+ g = brightness;
+ b = brightness;
+
+ red = (uint8) (r * 255 + 0.5);
+ green = (uint8) (g * 255 + 0.5);
+ blue = (uint8) (b * 255 + 0.5);
+
+ return;
+ }
+
+ hue /= 60;
+ i = (int) hue;
+ f = hue - i;
+ p = brightness * (1 - saturation);
+ q = brightness * (1 - saturation * f);
+ t = brightness * (1 - saturation * (1 - f));
+
+ switch (i) {
+ case 0:
+ r = brightness;
+ g = t;
+ b = p;
+ break;
+ case 1:
+ r = q;
+ g = brightness;
+ b = p;
+ break;
+ case 2:
+ r = p;
+ g = brightness;
+ b = t;
+ break;
+ case 3:
+ r = p;
+ g = q;
+ b = brightness;
+ break;
+ case 4:
+ r = t;
+ g = p;
+ b = brightness;
+ break;
+ default:
+ r = brightness;
+ g = p;
+ b = q;
+ break;
+ }
+
+ red = (uint8) (r * 255 + 0.5);
+ green = (uint8) (g * 255 + 0.5);
+ blue = (uint8) (b * 255 + 0.5);
+ }
+
+ public string to_hex () {
+ return "#%02x%02x%02x".printf (red, green, blue);
+ }
}
diff --git a/src/config/Constants.vala b/src/config/Constants.vala
index 1c17d67..1ebc517 100644
--- a/src/config/Constants.vala
+++ b/src/config/Constants.vala
@@ -23,5 +23,5 @@ namespace Config {
public const string APP_ID = "com.github.manexim.home";
public const string APP_AUTHOR = "Manexim";
public const string APP_NAME = "Home";
- public const string APP_VERSION = "0.4.2";
+ public const string APP_VERSION = "0.5.0";
}
diff --git a/src/controllers/DeviceController.vala b/src/controllers/DeviceController.vala
index cadd20f..fed60ca 100644
--- a/src/controllers/DeviceController.vala
+++ b/src/controllers/DeviceController.vala
@@ -34,6 +34,8 @@ public abstract class Controllers.DeviceController : Object {
public abstract void switch_brightness (uint16 brightness);
+ public abstract void switch_hsb (uint16 hue, uint16 saturation, uint16 brightness);
+
public abstract void switch_color_temperature (uint16 color_temperature);
public abstract void switch_power (bool on);
diff --git a/src/lifx/Controller.vala b/src/lifx/Controller.vala
index 16f3439..3518f4f 100644
--- a/src/lifx/Controller.vala
+++ b/src/lifx/Controller.vala
@@ -51,6 +51,15 @@ public class Lifx.Controller : Controllers.DeviceController {
lamp.brightness = brightness;
}
+ public override void switch_hsb (uint16 hue, uint16 saturation, uint16 brightness) {
+ var lamp = device as Lifx.Lamp;
+ service.set_color (lamp, hue, saturation, brightness, 0, 0);
+
+ lamp.hue = hue;
+ lamp.saturation = saturation;
+ lamp.brightness = brightness;
+ }
+
public override void switch_color_temperature (uint16 color_temperature) {
var lamp = device as Lifx.Lamp;
service.set_color (lamp, 0, 0, lamp.brightness, color_temperature, 0);
diff --git a/src/lifx/Packet.vala b/src/lifx/Packet.vala
index 19ffe7d..4694f7a 100644
--- a/src/lifx/Packet.vala
+++ b/src/lifx/Packet.vala
@@ -74,26 +74,26 @@ public class Lifx.Packet {
// payload
payload = new Json.Object ();
- const uint8 i = 36;
+ const uint8 INDEX = 36;
switch (type) {
case 3: // StateService
- payload.set_int_member ("service", buffer.read_uint8 (i));
- payload.set_int_member ("port", buffer.read_uint32_le (i + 1));
+ payload.set_int_member ("service", buffer.read_uint8 (INDEX));
+ payload.set_int_member ("port", buffer.read_uint32_le (INDEX + 1));
break;
case 13: // StateHostInfo
- payload.set_double_member ("signal", buffer.read_float_le (i));
- payload.set_int_member ("tx", buffer.read_uint32_le (i + 4));
- payload.set_int_member ("rx", buffer.read_uint32_le (i + 8));
+ payload.set_double_member ("signal", buffer.read_float_le (INDEX));
+ payload.set_int_member ("tx", buffer.read_uint32_le (INDEX + 4));
+ payload.set_int_member ("rx", buffer.read_uint32_le (INDEX + 8));
break;
case 15: // StateHostFirmware
- payload.set_double_member ("signal", buffer.read_float_le (i));
- payload.set_int_member ("tx", buffer.read_uint32_le (i + 4));
- payload.set_int_member ("rx", buffer.read_uint32_le (i + 8));
+ payload.set_double_member ("signal", buffer.read_float_le (INDEX));
+ payload.set_int_member ("tx", buffer.read_uint32_le (INDEX + 4));
+ payload.set_int_member ("rx", buffer.read_uint32_le (INDEX + 8));
break;
case 22: // StatePower
Types.Power power = Types.Power.UNKNOWN;
- uint16 power_t = buffer.read_uint16_le (i);
+ uint16 power_t = buffer.read_uint16_le (INDEX);
if (power_t > 0) {
power = Types.Power.ON;
} else if (power_t == 0) {
@@ -102,10 +102,10 @@ public class Lifx.Packet {
payload.set_int_member ("level", power);
break;
case 25: // StateLabel
- payload.set_string_member ("label", (string) buffer.slice (i, i + 32).raw);
+ payload.set_string_member ("label", (string) buffer.slice (INDEX, INDEX + 32).raw);
break;
case 33: // StateVersion
- uint32 product = buffer.read_uint32_le (i + 4);
+ uint32 product = buffer.read_uint32_le (INDEX + 4);
string model = "";
bool supports_color = false;
bool supports_infrared = false;
@@ -255,14 +255,14 @@ public class Lifx.Packet {
payload.set_boolean_member ("supportsMultizone", supports_multizone);
break;
case 107: // State
- payload.set_int_member ("hue", buffer.read_uint16_le (i));
- payload.set_int_member ("saturation", buffer.read_uint16_le (i + 2));
- payload.set_int_member ("brightness", buffer.read_uint16_le (i + 4));
- payload.set_int_member ("kelvin", buffer.read_uint16_le (i + 6));
+ payload.set_int_member ("hue", buffer.read_uint16_le (INDEX));
+ payload.set_int_member ("saturation", buffer.read_uint16_le (INDEX + 2));
+ payload.set_int_member ("brightness", buffer.read_uint16_le (INDEX + 4));
+ payload.set_int_member ("kelvin", buffer.read_uint16_le (INDEX + 6));
// power
Types.Power power = Types.Power.UNKNOWN;
- uint16 power_t = buffer.read_uint16_le (i + 10);
+ uint16 power_t = buffer.read_uint16_le (INDEX + 10);
if (power_t > 0) {
power = Types.Power.ON;
} else if (power_t == 0) {
@@ -270,11 +270,11 @@ public class Lifx.Packet {
}
payload.set_int_member ("power", power);
- payload.set_string_member ("label", (string) buffer.slice (i + 12, i + 44).raw);
+ payload.set_string_member ("label", (string) buffer.slice (INDEX + 12, INDEX + 44).raw);
break;
case 118: // StatePower
Types.Power power = Types.Power.UNKNOWN;
- uint16 power_t = buffer.read_uint16_le (i);
+ uint16 power_t = buffer.read_uint16_le (INDEX);
if (power_t > 0) {
power = Types.Power.ON;
} else if (power_t == 0) {
@@ -284,7 +284,7 @@ public class Lifx.Packet {
break;
default:
var a = new Json.Array ();
- var raw = buffer.slice (i, (uint8) size).raw;
+ var raw = buffer.slice (INDEX, (uint8) size).raw;
for (uint8 j = 0; j < raw.length; j++) {
a.add_int_element (raw[j]);
@@ -326,11 +326,11 @@ public class Lifx.Packet {
// frame address
Buffer buf2 = new Buffer.alloc (16);
for (uint8 i = 0; i < 8; i++) {
- buf2.write_uint8(target_parts[i], i);
+ buf2.write_uint8 (target_parts[i], i);
}
// header
- Buffer buf3 = new Buffer.alloc(12);
+ Buffer buf3 = new Buffer.alloc (12);
buf3.write_uint16_le (type, 8);
uint8 byte14 = (ack_required << 1) | res_required;
diff --git a/src/lifx/Service.vala b/src/lifx/Service.vala
index cb7fbb0..9b156fa 100644
--- a/src/lifx/Service.vala
+++ b/src/lifx/Service.vala
@@ -61,7 +61,9 @@ public class Lifx.Service {
}
}
- public void set_color (Lifx.Lamp lamp, uint16 hue, uint16 saturation, uint16 brightness, uint16 kelvin, uint32 duration=0) {
+ public void set_color (
+ Lifx.Lamp lamp, uint16 hue, uint16 saturation, uint16 brightness, uint16 kelvin, uint32 duration=0
+ ) {
var packet = new Lifx.Packet ();
packet.type = 102;
packet.tagged = false;
@@ -186,9 +188,9 @@ public class Lifx.Service {
#if HAVE_SO_REUSEPORT
int32 enable = 1;
- Posix.setsockopt(
+ Posix.setsockopt (
socket.fd, Platform.Socket.SOL_SOCKET, Platform.Socket.SO_REUSEPORT, &enable,
- (Posix.socklen_t) sizeof(int)
+ (Posix.socklen_t) sizeof (int)
);
#endif
diff --git a/src/meson.build b/src/meson.build
index be50a21..f49fff9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -36,6 +36,7 @@ sources = [
'views/Overview.vala',
'widgets/Carousel.vala',
'widgets/CarouselItem.vala',
+ 'widgets/ColorPicker.vala',
'widgets/IconPopover.vala',
'widgets/Overlay.vala',
'MainWindow.vala'
diff --git a/src/pages/DevicePage.vala b/src/pages/DevicePage.vala
index e964e81..ffff36a 100644
--- a/src/pages/DevicePage.vala
+++ b/src/pages/DevicePage.vala
@@ -21,6 +21,9 @@
public class Pages.DevicePage : Pages.AbstractDevicePage {
private Controllers.DeviceController controller;
+ private Gtk.Scale hue_scale;
+ private Gtk.Scale saturation_scale;
+ private Gtk.Scale brightness_scale;
public DevicePage (Models.Device device) {
Object (
@@ -43,7 +46,7 @@ public class Pages.DevicePage : Pages.AbstractDevicePage {
var hue_label = new Gtk.Label (_("Hue: "));
hue_label.xalign = 1;
- var hue_scale = new Gtk.Scale.with_range (
+ hue_scale = new Gtk.Scale.with_range (
Gtk.Orientation.HORIZONTAL, lamp.hue_min, lamp.hue_max, 1.0
);
@@ -63,7 +66,7 @@ public class Pages.DevicePage : Pages.AbstractDevicePage {
var saturation_label = new Gtk.Label (_("Saturation: "));
saturation_label.xalign = 1;
- var saturation_scale = new Gtk.Scale.with_range (
+ saturation_scale = new Gtk.Scale.with_range (
Gtk.Orientation.HORIZONTAL, lamp.saturation_min, lamp.saturation_max, 1.0
);
@@ -85,7 +88,7 @@ public class Pages.DevicePage : Pages.AbstractDevicePage {
var brightness_label = new Gtk.Label (_("Brightness: "));
brightness_label.xalign = 1;
- var brightness_scale = new Gtk.Scale.with_range (
+ brightness_scale = new Gtk.Scale.with_range (
Gtk.Orientation.HORIZONTAL, lamp.brightness_min, lamp.brightness_max, 1.0
);
@@ -124,6 +127,42 @@ public class Pages.DevicePage : Pages.AbstractDevicePage {
content_area.attach (color_temperature_label, 0, 3, 1, 1);
content_area.attach (color_temperature_scale, 1, 3, 1, 1);
}
+
+ if (lamp.supports_color) {
+ var c = new Colors.HSB ();
+ c.hue = remap_value (lamp.hue, lamp.hue_min, lamp.hue_max, 0, 360);
+ c.saturation = (uint8) remap_value (lamp.saturation, lamp.saturation_min, lamp.saturation_max, 0, 100);
+ c.brightness = (uint8) remap_value (lamp.brightness, lamp.brightness_min, lamp.brightness_max, 0, 100);
+
+ var color_picker = new Widgets.ColorPicker (MainWindow.get_default ());
+ color_picker.hsb = c;
+ color_picker.on_color_change.connect ((rgb) => {
+ var hsb = new Colors.HSB.from_rgb (rgb);
+
+ var hue = remap_value (hsb.hue, 0, 360, lamp.hue_min, lamp.hue_max);
+ var saturation = remap_value (hsb.saturation, 0, 100, lamp.saturation_min, lamp.saturation_max);
+ var brightness = remap_value (hsb.brightness, 0, 100, lamp.brightness_min, lamp.brightness_max);
+
+ #if DEMO_MODE
+ hue_scale.adjustment.value = hue;
+ lamp.hue = hue_scale.adjustment.value;
+
+ saturation_scale.adjustment.value = saturation;
+ lamp.saturation = saturation_scale.adjustment.value;
+
+ brightness_scale.adjustment.value = brightness;
+ lamp.brightness = brightness_scale.adjustment.value;
+ #else
+ controller.switch_hsb (hue, saturation, brightness);
+
+ hue_scale.adjustment.value = hue;
+ saturation_scale.adjustment.value = saturation;
+ brightness_scale.adjustment.value = brightness;
+ #endif
+ });
+
+ content_area.attach (color_picker, 0, 4, 1, 1);
+ }
}
controller.device.notify.connect (update_status);
@@ -178,4 +217,8 @@ public class Pages.DevicePage : Pages.AbstractDevicePage {
break;
}
}
+
+ private uint16 remap_value (uint16 value, uint16 in_min, uint16 in_max, uint16 out_min, uint16 out_max) {
+ return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+ }
}
diff --git a/src/pages/HueBridgeOnboardingPage.vala b/src/pages/HueBridgeOnboardingPage.vala
index db68494..1e1dba7 100644
--- a/src/pages/HueBridgeOnboardingPage.vala
+++ b/src/pages/HueBridgeOnboardingPage.vala
@@ -38,7 +38,7 @@ public class Pages.HueBridgeOnboardingPage : Gtk.Grid {
label = new Gtk.Label (_("Press the push-link button in the middle of the Hue bridge."));
spinner = new Gtk.Spinner ();
- spinner.start ();
+ spinner.start ();
attach (icon, 0, 0, 1, 1);
attach (label, 0, 1, 1, 1);
diff --git a/src/pages/LoadingPage.vala b/src/pages/LoadingPage.vala
index 3703ead..4d8fa17 100644
--- a/src/pages/LoadingPage.vala
+++ b/src/pages/LoadingPage.vala
@@ -25,13 +25,13 @@ public class Pages.LoadingPage : Gtk.Grid {
valign = Gtk.Align.CENTER;
var label = new Gtk.Label (_("Looking for smart home gadgets to control."));
- label.halign = Gtk.Align.CENTER;
- label.valign = Gtk.Align.CENTER;
+ label.halign = Gtk.Align.CENTER;
+ label.valign = Gtk.Align.CENTER;
var spinner = new Gtk.Spinner ();
- spinner.halign = Gtk.Align.CENTER;
- spinner.valign = Gtk.Align.CENTER;
- spinner.start ();
+ spinner.halign = Gtk.Align.CENTER;
+ spinner.valign = Gtk.Align.CENTER;
+ spinner.start ();
attach (label, 0, 0, 1, 1);
attach (spinner, 0, 2, 1, 1);
diff --git a/src/philips/hue/BridgeController.vala b/src/philips/hue/BridgeController.vala
index 4bc0c4b..a58917f 100644
--- a/src/philips/hue/BridgeController.vala
+++ b/src/philips/hue/BridgeController.vala
@@ -43,12 +43,15 @@ public class Philips.Hue.BridgeController {
session.send_message (message);
- // replace with
- // because otherwise the node can not be found
- GLib.Regex r = /.*().*/;
Xml.Doc* doc;
try {
- var patched = r.replace ((string) message.response_body.data, (ssize_t) message.response_body.length, 0, "");
+ // replace with
+ // because otherwise the node can not be found
+ var r = new Regex (".*().*");
+
+ var patched = r.replace (
+ (string) message.response_body.data, (ssize_t) message.response_body.length, 0, ""
+ );
Xml.Parser.init ();
@@ -57,19 +60,19 @@ public class Philips.Hue.BridgeController {
stderr.printf ("failed to read the .xml file\n");
}
- Xml.XPath.Context context = new Xml.XPath.Context(doc);
+ Xml.XPath.Context context = new Xml.XPath.Context (doc);
if (context == null) {
stderr.printf ("failed to create the xpath context\n");
}
- Xml.XPath.Object* obj = context.eval_expression("/root/device/friendlyName");
+ Xml.XPath.Object* obj = context.eval_expression ("/root/device/friendlyName");
if (obj == null) {
stderr.printf ("failed to evaluate xpath\n");
}
Xml.Node* node = null;
- if (obj->nodesetval != null && obj->nodesetval->item(0) != null) {
- node = obj->nodesetval->item(0);
+ if (obj->nodesetval != null && obj->nodesetval->item (0) != null) {
+ node = obj->nodesetval->item (0);
} else {
stderr.printf ("failed to find the expected node\n");
}
@@ -78,14 +81,14 @@ public class Philips.Hue.BridgeController {
delete obj;
- obj = context.eval_expression("/root/device/manufacturer");
+ obj = context.eval_expression ("/root/device/manufacturer");
if (obj == null) {
stderr.printf ("failed to evaluate xpath\n");
}
node = null;
- if (obj->nodesetval != null && obj->nodesetval->item(0) != null) {
- node = obj->nodesetval->item(0);
+ if (obj->nodesetval != null && obj->nodesetval->item (0) != null) {
+ node = obj->nodesetval->item (0);
} else {
stderr.printf ("failed to find the expected node\n");
}
@@ -94,14 +97,14 @@ public class Philips.Hue.BridgeController {
delete obj;
- obj = context.eval_expression("/root/device/modelName");
+ obj = context.eval_expression ("/root/device/modelName");
if (obj == null) {
stderr.printf ("failed to evaluate xpath\n");
}
node = null;
- if (obj->nodesetval != null && obj->nodesetval->item(0) != null) {
- node = obj->nodesetval->item(0);
+ if (obj->nodesetval != null && obj->nodesetval->item (0) != null) {
+ node = obj->nodesetval->item (0);
} else {
stderr.printf ("failed to find the expected node\n");
}
@@ -109,7 +112,7 @@ public class Philips.Hue.BridgeController {
_bridge.model = node->get_content ();
delete obj;
- } catch (GLib.RegexError e) {
+ } catch (RegexError e) {
stderr.printf (e.message);
} finally {
delete doc;
@@ -118,7 +121,7 @@ public class Philips.Hue.BridgeController {
Xml.Parser.cleanup ();
}
- public bool register () throws GLib.Error {
+ public bool register () throws Error {
#if DEMO_MODE
if (register_counter++ == 2) {
_bridge.power = Types.Power.ON;
@@ -149,15 +152,15 @@ public class Philips.Hue.BridgeController {
string response = (string) message.response_body.flatten ().data;
- var parser = new Json.Parser();
+ var parser = new Json.Parser ();
parser.load_from_data (response, -1);
foreach (var element in parser.get_root ().get_array ().get_elements ()) {
var obj = element.get_object ();
if (obj.has_member ("error")) {
- throw new GLib.Error (
- GLib.Quark.from_string (""),
+ throw new Error (
+ Quark.from_string (""),
(int) obj.get_object_member ("error").get_int_member ("type"),
obj.get_object_member ("error").get_string_member ("description")
);
@@ -184,7 +187,7 @@ public class Philips.Hue.BridgeController {
string response = (string) message.response_body.flatten ().data;
try {
- var parser = new Json.Parser();
+ var parser = new Json.Parser ();
parser.load_from_data (response, -1);
var object = parser.get_root ().get_object ();
var lights = object.get_object_member ("lights");
@@ -207,7 +210,8 @@ public class Philips.Hue.BridgeController {
if (light.get_object_member ("state").has_member ("ct")) {
lamp.supports_color_temperature = true;
- lamp.color_temperature = (uint16) (1000000.0 / light.get_object_member ("state").get_int_member ("ct"));
+ lamp.color_temperature = (uint16) (1000000.0 / light.get_object_member ("state")
+ .get_int_member ("ct"));
}
if (light.get_object_member ("state").has_member ("hue")) {
@@ -241,7 +245,7 @@ public class Philips.Hue.BridgeController {
on_updated_lamp (lamp);
}
}
- } catch (GLib.Error e) {
+ } catch (Error e) {
stderr.printf (e.message);
}
}
@@ -274,6 +278,15 @@ public class Philips.Hue.BridgeController {
switch_light_state (lamp, state);
}
+ public void switch_light_hsb (Philips.Hue.Lamp lamp, uint16 hue, uint16 saturation, uint16 brightness) {
+ var state = new Json.Object ();
+ state.set_int_member ("hue", hue);
+ state.set_int_member ("sat", saturation);
+ state.set_int_member ("bri", brightness);
+
+ switch_light_state (lamp, state);
+ }
+
public void switch_light_color_temperature (Philips.Hue.Lamp lamp, uint16 color_temperature) {
var state = new Json.Object ();
state.set_int_member ("ct", (uint16) (1000000 / color_temperature));
diff --git a/src/philips/hue/Controller.vala b/src/philips/hue/Controller.vala
index 088c5d0..cffbd32 100644
--- a/src/philips/hue/Controller.vala
+++ b/src/philips/hue/Controller.vala
@@ -51,6 +51,15 @@ public class Philips.Hue.Controller : Controllers.DeviceController {
lamp.brightness = brightness;
}
+ public override void switch_hsb (uint16 hue, uint16 saturation, uint16 brightness) {
+ var lamp = device as Philips.Hue.Lamp;
+ controller.switch_light_hsb (lamp, hue, saturation, brightness);
+
+ lamp.hue = hue;
+ lamp.saturation = saturation;
+ lamp.brightness = brightness;
+ }
+
public override void switch_color_temperature (uint16 color_temperature) {
var lamp = device as Philips.Hue.Lamp;
controller.switch_light_color_temperature (lamp, color_temperature);
diff --git a/src/philips/hue/Service.vala b/src/philips/hue/Service.vala
index 0dba059..bdf311c 100644
--- a/src/philips/hue/Service.vala
+++ b/src/philips/hue/Service.vala
@@ -121,9 +121,9 @@ public class Philips.Hue.Service {
#if HAVE_SO_REUSEPORT
int32 enable = 1;
- Posix.setsockopt(
+ Posix.setsockopt (
socket.fd, Platform.Socket.SOL_SOCKET, Platform.Socket.SO_REUSEPORT, &enable,
- (Posix.socklen_t) sizeof(int)
+ (Posix.socklen_t) sizeof (int)
);
#endif
@@ -144,7 +144,7 @@ public class Philips.Hue.Service {
size_t read = s.receive (buffer);
buffer[read] = 0; // null-terminate string
- GLib.Regex r_hue_bridgeid = /.*hue-bridgeid:\s*([^\s]*).*/;
+ var r_hue_bridgeid = new GLib.Regex (".*hue-bridgeid:\\s*([^\\s]*).*");
string hue_bridgeid;
GLib.MatchInfo mi;
if (r_hue_bridgeid.match ((string) buffer, 0, out mi)) {
@@ -244,22 +244,26 @@ public class Philips.Hue.Service {
}
private void found_bridge_ssdp (string bridgeid, string message) {
- GLib.Regex r_location = /.*LOCATION:\s*((http:\/\/)(.*):(\d*)([^\s]*)).*/;
- string url, protocol, host, port, path;
- GLib.MatchInfo mi;
- if (r_location.match (message, 0, out mi)) {
- url = mi.fetch (1);
- protocol = mi.fetch (2);
- host = mi.fetch (3);
- port = mi.fetch (4);
- path = mi.fetch (5);
-
- var bridge = new Bridge ();
- bridge.id = bridgeid.up ();
- bridge.base_url = protocol + host + ":" + port + "/";
-
- found_bridge (bridge);
+ try {
+ var r_location = new Regex (".*LOCATION:\\s*((http:\\/\\/)(.*):(\\d*)([^\\s]*)).*");
+ string url, protocol, host, port, path;
+ GLib.MatchInfo mi;
+ if (r_location.match (message, 0, out mi)) {
+ url = mi.fetch (1);
+ protocol = mi.fetch (2);
+ host = mi.fetch (3);
+ port = mi.fetch (4);
+ path = mi.fetch (5);
+
+ var bridge = new Bridge ();
+ bridge.id = bridgeid.up ();
+ bridge.base_url = protocol + host + ":" + port + "/";
+
+ found_bridge (bridge);
+ }
+ } catch (RegexError e) {
+ stderr.printf (e.message);
}
}
diff --git a/src/services/Settings.vala b/src/services/Settings.vala
index 20323f2..52f057a 100644
--- a/src/services/Settings.vala
+++ b/src/services/Settings.vala
@@ -75,7 +75,7 @@ public class Settings : Granite.Services.Settings {
return true;
},
(value, expected_type) => {
- return new Variant.string(value.get_boolean() ? "dark" : "no-preference");
+ return new Variant.string (value.get_boolean () ? "dark" : "no-preference");
},
null,
null
@@ -102,7 +102,7 @@ public class Settings : Granite.Services.Settings {
}
public Json.Object configuration_as_json () throws GLib.Error {
- var parser = new Json.Parser();
+ var parser = new Json.Parser ();
parser.load_from_data (configuration, -1);
var object = parser.get_root ().get_object ();
diff --git a/src/types/Power.vala b/src/types/Power.vala
index 6e00f60..6a578dc 100644
--- a/src/types/Power.vala
+++ b/src/types/Power.vala
@@ -25,7 +25,7 @@ public enum Types.Power {
OFF = 0,
ON = 65535;
- public string to_string() {
+ public string to_string () {
switch (this) {
case UNKNOWN:
return "unknown";
@@ -37,7 +37,7 @@ public enum Types.Power {
return "on";
default:
print ("ERROR: Unsupported value %d\n", this);
- assert_not_reached();
+ assert_not_reached ();
}
}
}
diff --git a/src/utils/Buffer.vala b/src/utils/Buffer.vala
index 185efa4..fd20db0 100644
--- a/src/utils/Buffer.vala
+++ b/src/utils/Buffer.vala
@@ -51,40 +51,40 @@ public class Buffer {
return offset + 1;
}
- private uint16 readUInt16Backwards (uint8 offset) {
+ private uint16 read_uint16_backwards (uint8 offset) {
return this.values[offset + 1]
| (this.values[offset] << 8);
}
- private uint16 readUInt16Forwards (uint8 offset) {
+ private uint16 read_uint16_forwards (uint8 offset) {
return this.values[offset]
| (this.values[offset + 1] << 8);
}
public uint16 read_uint16_be (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readUInt16Forwards (offset);
+ return this.read_uint16_forwards (offset);
}
- return this.readUInt16Backwards (offset);
+ return this.read_uint16_backwards (offset);
}
public uint16 read_uint16_le (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readUInt16Backwards (offset);
+ return this.read_uint16_backwards (offset);
}
- return this.readUInt16Forwards (offset);
+ return this.read_uint16_forwards (offset);
}
- private uint8 writeUInt16Backwards (uint16 value, uint8 offset) {
+ private uint8 writer_uint16_backwards (uint16 value, uint8 offset) {
this.values[offset + 1] = (uint8) (value & 0xff);
this.values[offset] = (uint8) ((value >> 8) & 0xff);
return offset + 2;
}
- private uint8 writeUInt16Forwards (uint16 value, uint8 offset) {
+ private uint8 write_uint16_forwards (uint16 value, uint8 offset) {
this.values[offset] = (uint8) (value & 0xff);
this.values[offset + 1] = (uint8) ((value >> 8) & 0xff);
@@ -93,28 +93,28 @@ public class Buffer {
public uint8 write_uint16_be (uint16 value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeUInt16Forwards (value, offset);
+ return this.write_uint16_forwards (value, offset);
}
- return this.writeUInt16Backwards (value, offset);
+ return this.writer_uint16_backwards (value, offset);
}
public uint8 write_uint16_le (uint16 value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeUInt16Backwards (value, offset);
+ return this.writer_uint16_backwards (value, offset);
}
- return this.writeUInt16Forwards (value, offset);
+ return this.write_uint16_forwards (value, offset);
}
- private uint32 readUInt32Backwards (uint8 offset) {
+ private uint32 read_uint32_backwards (uint8 offset) {
return this.values[offset + 3]
| (this.values[offset + 2] << 8)
| (this.values[offset + 1] << 16)
| (this.values[offset] << 24);
}
- private uint32 readUInt32Forwards (uint8 offset) {
+ private uint32 read_uint32_forwards (uint8 offset) {
return this.values[offset]
| (this.values[offset + 1] << 8)
| (this.values[offset + 2] << 16)
@@ -123,21 +123,21 @@ public class Buffer {
public uint32 read_uint32_be (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readUInt32Forwards (offset);
+ return this.read_uint32_forwards (offset);
}
- return this.readUInt32Backwards (offset);
+ return this.read_uint32_backwards (offset);
}
public uint32 read_uint32_le (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readUInt32Backwards (offset);
+ return this.read_uint32_backwards (offset);
}
- return this.readUInt32Forwards (offset);
+ return this.read_uint32_forwards (offset);
}
- private uint8 writeUInt32Backwards (uint32 value, uint8 offset) {
+ private uint8 write_uint32_backwards (uint32 value, uint8 offset) {
this.values[offset + 3] = (uint8) (value & 0xff);
this.values[offset + 2] = (uint8) ((value >> 8) & 0xff);
this.values[offset + 1] = (uint8) ((value >> 16) & 0xff);
@@ -146,7 +146,7 @@ public class Buffer {
return offset + 4;
}
- private uint8 writeUInt32Forwards (uint32 value, uint8 offset) {
+ private uint8 write_uint32_forwards (uint32 value, uint8 offset) {
this.values[offset] = (uint8) (value & 0xff);
this.values[offset + 1] = (uint8) ((value >> 8) & 0xff);
this.values[offset + 2] = (uint8) ((value >> 16) & 0xff);
@@ -157,28 +157,28 @@ public class Buffer {
public uint8 write_uint32_be (uint32 value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeUInt32Forwards (value, offset);
+ return this.write_uint32_forwards (value, offset);
}
- return this.writeUInt32Backwards (value, offset);
+ return this.write_uint32_backwards (value, offset);
}
public uint8 write_uint32_le (uint32 value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeUInt32Backwards (value, offset);
+ return this.write_uint32_backwards (value, offset);
}
- return this.writeUInt32Forwards (value, offset);
+ return this.write_uint32_forwards (value, offset);
}
- private float readFloatBackwards (uint8 offset) {
+ private float read_float_backwards (uint8 offset) {
float f = (float) 0.0;
Posix.memcpy (&f, &this.values[offset], 4);
return f;
}
- private float readFloatForwards (uint8 offset) {
+ private float read_float_forwards (uint8 offset) {
float f = (float) 0.0;
Posix.memcpy (&f, &this.values[offset], 4);
@@ -187,27 +187,27 @@ public class Buffer {
public float read_float_be (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readFloatForwards (offset);
+ return this.read_float_forwards (offset);
}
- return this.readFloatBackwards (offset);
+ return this.read_float_backwards (offset);
}
public float read_float_le (uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.readFloatBackwards (offset);
+ return this.read_float_backwards (offset);
}
- return this.readFloatForwards (offset);
+ return this.read_float_forwards (offset);
}
- private uint8 writeFloatBackwards (float value, uint8 offset) {
+ private uint8 write_float_backwards (float value, uint8 offset) {
Posix.memcpy (&this.values[offset], &value, 4);
return 4;
}
- private uint8 writeFloatForwards (float value, uint8 offset) {
+ private uint8 write_float_forwards (float value, uint8 offset) {
Posix.memcpy (&this.values[offset], &value, 4);
return 4;
@@ -215,18 +215,18 @@ public class Buffer {
public uint8 write_float_be (float value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeFloatForwards (value, offset);
+ return this.write_float_forwards (value, offset);
}
- return this.writeFloatBackwards (value, offset);
+ return this.write_float_backwards (value, offset);
}
public uint8 write_float_le (float value, uint8 offset) {
if (Platform.is_big_endian ()) {
- return this.writeFloatBackwards (value, offset);
+ return this.write_float_backwards (value, offset);
}
- return this.writeFloatForwards (value, offset);
+ return this.write_float_forwards (value, offset);
}
public Buffer concat (Buffer list) {
diff --git a/src/views/Overview.vala b/src/views/Overview.vala
index 2e6f81f..6a3342d 100644
--- a/src/views/Overview.vala
+++ b/src/views/Overview.vala
@@ -21,11 +21,33 @@
public class Views.Overview : Gtk.ScrolledWindow {
private Controllers.DevicesController devices_controller;
+ private Gtk.Stack stack;
+ private Gtk.Grid network_view;
+ private Gtk.Grid grid;
public Overview () {
- var grid = new Gtk.Grid ();
+ var network_alert_view = new Granite.Widgets.AlertView (
+ _("Network Is Not Available"),
+ _("Connect to the network to control your smart home gadgets."),
+ "network-error"
+ );
+ network_alert_view.get_style_context ().remove_class (Gtk.STYLE_CLASS_VIEW);
+ network_alert_view.show_action (_("Network Settings…"));
+
+ network_view = new Gtk.Grid ();
+ network_view.margin = 24;
+ network_view.attach (network_alert_view, 0, 0, 1, 1);
+
+ stack = new Gtk.Stack ();
+ stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
+
+ grid = new Gtk.Grid ();
grid.margin = 12;
- add (grid);
+
+ stack.add (grid);
+ stack.add (network_view);
+
+ add (stack);
var loading_revealer = new Gtk.Revealer ();
loading_revealer.add (new Pages.LoadingPage ());
@@ -90,8 +112,8 @@ public class Views.Overview : Gtk.ScrolledWindow {
grid.attach (hubs_revealer, 0, 2, 1, 1);
- var philipsHueService = Philips.Hue.Service.instance;
- philipsHueService.on_new_bridge.connect ((bridge) => {
+ var philips_hue_service = Philips.Hue.Service.instance;
+ philips_hue_service.on_new_bridge.connect ((bridge) => {
if (loading_revealer.child_revealed) {
loading_revealer.reveal_child = false;
}
@@ -108,5 +130,24 @@ public class Views.Overview : Gtk.ScrolledWindow {
);
}
});
+
+ NetworkMonitor.get_default ().network_changed.connect (on_view_mode_changed);
+
+ network_alert_view.action_activated.connect (() => {
+ try {
+ AppInfo.launch_default_for_uri ("settings://network", null);
+ } catch (Error e) {
+ warning (e.message);
+ }
+ });
+ }
+
+ private void on_view_mode_changed () {
+ var connection_available = NetworkMonitor.get_default ().get_network_available ();
+ if (!connection_available) {
+ stack.visible_child = network_view;
+ } else {
+ stack.visible_child = grid;
+ }
}
}
diff --git a/src/widgets/ColorPicker.vala b/src/widgets/ColorPicker.vala
new file mode 100644
index 0000000..07603e3
--- /dev/null
+++ b/src/widgets/ColorPicker.vala
@@ -0,0 +1,88 @@
+public class Widgets.ColorPicker: Gtk.DrawingArea {
+ private Gdk.RGBA color;
+ private Gtk.Window window;
+ private bool dialog_visible;
+
+ public signal void on_color_change (Colors.RGB color);
+
+ public ColorPicker (Gtk.Window window) {
+ this.window = window;
+ color.parse ("#4caf50");
+
+ set_size_request (140, 140);
+ add_events (Gdk.EventMask.ALL_EVENTS_MASK);
+
+ button_press_event.connect ((event) => {
+ if (event.button == 1 && !dialog_visible) {
+ var dialog = new Gtk.ColorSelectionDialog ("");
+ unowned Gtk.ColorSelection widget = dialog.get_color_selection ();
+
+ widget.current_rgba = color;
+
+ dialog.deletable = false;
+ dialog.transient_for = window;
+ dialog_visible = true;
+
+ if (dialog.run () == Gtk.ResponseType.OK) {
+ if (color != widget.current_rgba) {
+ color = widget.current_rgba;
+
+ var rgb = new Colors.RGB ();
+ rgb.red = (uint8) (color.red * 255 + 0.5);
+ rgb.green = (uint8) (color.green * 255 + 0.5);
+ rgb.blue = (uint8) (color.blue * 255 + 0.5);
+
+ on_color_change (rgb);
+ }
+ }
+
+ dialog_visible = false;
+ dialog.close ();
+ }
+
+ return true;
+ });
+ }
+
+ public override bool draw (Cairo.Context ctx) {
+ int width = get_allocated_width ();
+ int height = get_allocated_height ();
+
+ // Draw an arc:
+ double xc = width / 2.0;
+ double yc = height / 2.0;
+ double radius = (int.min (width, height) / 2.0);
+ double angle1 = 0;
+ double angle2 = 2 * Math.PI;
+
+ int shadow_width = 6;
+ double shadow_alpha = 1.0;
+ string shadow_color = "#A9A9A9";
+ for (int i = 1; i <= shadow_width; i++) {
+ ctx.arc (xc, yc, radius - i, angle1, angle2);
+ Gdk.RGBA c = Gdk.RGBA ();
+ c.parse (shadow_color);
+ c.alpha = shadow_alpha / ((shadow_width - i + 1) * (shadow_width - i + 1));
+ Gdk.cairo_set_source_rgba (ctx, c);
+ ctx.stroke ();
+ }
+
+ ctx.arc (xc, yc, radius - shadow_width, angle1, angle2);
+ Gdk.cairo_set_source_rgba (ctx, color);
+ ctx.fill ();
+
+ return true;
+ }
+
+ public Colors.RGB rgb {
+ set {
+ color.parse (value.to_hex ());
+ }
+ }
+
+ public Colors.HSB hsb {
+ set {
+ color.parse (new Colors.RGB.from_hsb (value).to_hex ());
+ }
+ }
+}