Coder Social home page Coder Social logo

huex's Introduction

Huex

Elixir client for Philips Hue connected light bulbs.

Installation

Add Huex as a dependency in your mix.exs file.

def deps do
  [{:huex, "~> 0.8"}]
end

Also add HTTPoison as part of your applications, in your mix.exs file.

def application do
  [mod: {YourApp, []},
   applications: [:httpoison]]
end

After you are done, run mix deps.get in your shell to fetch and compile Huex.

Usage

First Connection

In order to issue queries and commands to the bridge, we need to request an authorization for a so-called devicetype (see Hue Configuration API) which is a string formatted as such: my-app#my-device.

Before requesting the authorization: you must press the link button on your bridge device to start a 30 second window during which you may request an authorization as follow:

bridge = Huex.connect("192.168.1.100") |> Huex.authorize("my-app#my-device")

# A random username is now set
IO.puts bridge.username
# YApVhLTwWUTlGJDo...

# The bridge connection is now ready for use
IO.inspect Huex.info(bridge)
# %{"config" => ...}

Subsequent Connections

Once a devicetype has been authorized with the bridge, there's no need to perform the authorization process again. In other words, you must store the generated username received set by authorize/2. With the username at hand, you can connect right away:

bridge = Huex.connect("192.168.1.100", "YApVhLTwWUTlGJDo...")

IO.inspect Huex.info(bridge)
# %{"config" => ...}

Bridge IP address discovery

You may use Huex.Discovery.discover/0 to retrieve a list of bridges on your network using SSDP:

Huex.Discovery.discover
# ["192.168.1.43"]

This optional feature depends on nerves_ssdp_client which must be added explicitly to your own application dependencies in mix.exs:

def deps do
  [{:huex, "~> 0.7"},
   {:nerves_ssdp_client, "~> 0.1"}]
end

Queries

Query functions return the message received from the bridge API.

IO.inspect Huex.info(bridge)
# %{"config" => %{"UTC" => "1970-01-01T03:00:40", "dhcp" => true,
#   "gateway" => "192.168.1.1", "ipaddress" => "192.168.1.100",
#    ...
#   "schedules" => %{}}

IO.inspect Huex.lights(bridge)
# %{"1" => %{"name" => "Lobby"}, "2" => %{"name" => "Living Room"},
#    "3" => %{"name" => "Bedroom"}}

IO.inspect Huex.light_info(bridge, 1)
# %{"modelid" => "LCT001", "name" => "Lobby",
#   ...
#   "swversion" => "66009663", "type" => "Extended color light"}

Commands

Command functions return a Huex.Bridge struct and are thus chainable.

bridge
|> Huex.turn_off(1)                                  # Turn off light 1
|> Huex.turn_on(2)                                   # Turn on light 2
|> Huex.set_color(2, {10000, 255, 255})              # HSV
|> Huex.set_color(2, {0.167, 0.04})                  # XY
|> Huex.set_color(2, Huex.Color.rgb(1, 0.75, 0.25))  # RGB (see limitations)
|> Huex.set_brightness(2, 0.75)                      # Brightness at 75%

Error Handling

For error handling, the Huex.Bridge struct has a status attribute which is either set to :ok or :error by command functions.

When an error occured, the complete error response is stored in the error attribute of the Huex.Bridge struct.

Examples

Look into the examples directory for more advanced usage examples.

Current Limitations

Color space conversion from RGB to XY currently feels a little fishy: I can't seem to get bright green or red using the given formula.

To Do

  • Reliable color conversion from RGB

Contributors

In order of appearance:

License

Copyright 2014 Xavier Defrang

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

huex's People

Contributors

xavier avatar mrbriandavis avatar arijitdasgupta avatar tehviking avatar derekkraan avatar eljojo avatar pkazmier avatar

Stargazers

Simon Hansen avatar  avatar Fabrizio Sestito avatar Luca Ongaro avatar Dorian Karter avatar Jen Stehlik avatar Henning Dahlheim avatar Eliel Gordon avatar Clay avatar  avatar Debajit Adhikary avatar David Dias avatar Meng Lim avatar Patrick Smith avatar Peter W. avatar jna avatar  avatar Cayo Medeiros avatar Sammy Taylor avatar May Matyi avatar Justin Workman avatar chakming avatar Sérgio Hilgert avatar Mark Sadegi avatar Zsolt Keszthelyi avatar Sam Gaw avatar Sidney Kochman avatar Ismail UNAL avatar Ivan Santos avatar Panagiotis PJ Papadomitsos avatar Marcus Bernales avatar Jesse Schoch avatar Peter avatar Richard Diamond avatar  avatar Miki Oracle avatar Daniel Sam avatar Jeff Ramer avatar hayley avatar Erol KOCAMAN avatar James G. Best avatar Kyle Decot avatar  avatar Arnaud Lécuyer avatar Cameron Irmas avatar Jeroen Visser avatar Andreas Guther avatar Jody Albritton avatar Zethus Suen avatar  avatar Rodrigo Franco avatar Drew Kerrigan avatar Stuart Bain avatar Christian Nilsson avatar Christopher Coté avatar Ben Parnell avatar Brian avatar Zura Guerra avatar Petter Rasmussen avatar Jonathan Merriweather avatar  avatar Ryan Plessner avatar Bilal Quadri avatar Marc Addeo avatar

Watchers

 avatar Sébastien Delneste avatar Philipp Böcker avatar Andreas Guther avatar  avatar

huex's Issues

Possibly out of date with Philips Hue API

It appears that the package is using a slightly older version of the Philips Hue API, that's no longer supported.

Authorization isn't done with a separate username param now, according to the API docs:

iex(1)> bridge = Huex.connect("192.168.0.20") |> Huex.authorize("huetest")
%Huex.Bridge{error: [%{"error" => %{"address" => "/username",
      "description" => "parameter, username, not available", "type" => 6}}],
 host: "192.168.0.20", status: :error, username: "huetest"}

I was able to make it work with the following change:

-  @spec authorize(Bridge.t, binary) :: Bridge.t
-  def authorize(bridge, username) do
-    payload = %{devicetype: "test user", username: username}
+  @spec authorize(Bridge.t, String.t, String.t, String.t) :: Bridge.t
+  def authorize(bridge, application_name, device_type, username) do
+    payload = %{devicetype: application_name <> "#" <> device_type <> " " <> username}
     bridge = bridge |> api_url |> post_json(payload) |> update_bridge(bridge)
     %Bridge{bridge | username: username}
   end

Example:

iex(3)> bridge = Huex.connect("192.168.0.20") |> Huex.authorize("huetest", "elixir", "huetest")
%Huex.Bridge{error: [%{"error" => %{"address" => "",
      "description" => "link button not pressed", "type" => 101}}],
 host: "192.168.0.20", status: :error, username: "huetest"}
iex(4)> bridge = Huex.connect("192.168.0.20") |> Huex.authorize("huetest", "elixir", "huetest")
%Huex.Bridge{error: nil, host: "192.168.0.20", status: :ok, username: "huetest"}

This doesn't appear to be the end of the API mismatch problems, however:

iex(5)> Huex.info(bridge)
[%{"error" => %{"address" => "/", "description" => "unauthorized user",
     "type" => 1}}]
iex(6)> bridge
%Huex.Bridge{error: nil, host: "192.168.0.20", status: :ok, username: "huetest"}
iex(7)> Huex.lights(bridge)
[%{"error" => %{"address" => "/lights", "description" => "unauthorized user",
     "type" => 1}}]

As I have a pretty extensive Philips Hue setup in my house and am excited about automating it, I'm happy to assist, but I wasn't sure what the plans with the package may be. Please let me know.

No process while attempting to run examples

Forgive my lack of experience with Elixir; I'm having a hard time getting the examples working in IEx. Am I missing some kind of initialisation step?

Many thanks!

(I'm attempting to connect to this Hue Emulator, hence the port number in the first argument, but as you can see, Huex is failing before it opens any connections)

iex(1)> bridge = Huex.connect("127.0.0.1:8000") |> Huex.authorize("my_app#my_device")
** (exit) exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.283.0>, #Reference<0.0.1.971>, {:client, :undefined, {:metrics_ng, :metrics_dummy}, :hackney_tcp, '127.0.0.1', 4001, "127.0.0.1:4001", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity)
    ** (EXIT) no process
    (stdlib) gen_server.erl:212: :gen_server.call/3
             deps/hackney/src/hackney_manager.erl:66: :hackney_manager.init_request/1
             deps/hackney/src/hackney_manager.erl:56: :hackney_manager.new_request/1
             deps/hackney/src/hackney_connect.erl:185: :hackney_connect.socket_from_pool/4
             deps/hackney/src/hackney_connect.erl:37: :hackney_connect.connect/5
             deps/hackney/src/hackney.erl:328: :hackney.request/5
             lib/httpoison/base.ex:402: HTTPoison.Base.request/9
             lib/huex.ex:381: Huex.post_json/2

(Mix) Could not compile dependency :hackney

I am not able to run the application with my current configuration.

MacBook-Pro:huex aguther$ mix deps.get
Running dependency resolution
* Getting hackney (Hex package)
  Checking package (https://repo.hex.pm/tarballs/hackney-1.6.1.tar)
  Using locally cached package
Andreass-MacBook-Pro:huex aguther$ mix test
escript: exception error: no function clause matching 
                 rebar_packages:format_error({missing_package,<<"certifi">>,
                                              <<"0.4.0">>}) (/private/tmp/rebar3-20160904-12837-smij8/rebar3-3.3.0/_build/default/lib/rebar/src/rebar_packages.erl, line 219)
  in function  rebar3:handle_error/1 (/private/tmp/rebar3-20160904-12837-smij8/rebar3-3.3.0/_build/default/lib/rebar/src/rebar3.erl, line 280)
  in call from escript:run/2 (escript.erl, line 757)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1 
  in call from init:do_boot/3 
** (Mix) Could not compile dependency :hackney, "/usr/local/bin/rebar3 bare compile --paths "/Users/aguther/dev/languages/elixir/huex/_build/test/lib/*/ebin"" command failed. You can recompile this dependency with "mix deps.compile hackney", update it with "mix deps.update hackney" or clean it with "mix deps.clean hackney"
MacBook-Pro:huex aguther$ 

Recompile, update, and clean for this dependency did not resolve the problem.

My runtime

MacBook-Pro:huex aguther$ elixir -v
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.3

Any idea what might be missing here?

Mix.Config deprecation warning

Hello!

I love this great module, but I noticed a deprecation warning for Mix.Config when I run it.

warning: use Mix.Config is deprecated. Use the Config module instead config/config.exs:3
I think I can update it to avoid this warning, and I'll make a pull request when I get it sorted.

Cheers

Add support for groups?

First off, thanks for the awesome project, I was doing manual API calls in my Slack bot project but I'm now rewriting it to use this instead, it's really well written from what I can tell, and was easy to extend.

I created a fork that adds support for fetching and changing stuff for groups in the grossest and jankiest way possible.

It's my first elixir project so it's not something I'd issue a pull request for, but if you have any thoughts or pointers as to how to re-architect, I'm open to suggestions.

https://github.com/tehviking/huex

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.