Giter VIP home page Giter VIP logo

ruby_home's Introduction

Maintainability

ruby_home

ruby_home is an implementation of the HomeKit Accessory Protocol (HAP) to create your own HomeKit accessory in Ruby. HomeKit is a set of protocols and libraries to access devices for home automation. A non-commercial version of the protocol documentation is available on the HomeKit developer website.

Installation

libsodium

To use ruby_home, you will need to install libsodium:

At least version 1.0.9 is required.

For OS X users, libsodium is available via homebrew and can be installed with:

brew install libsodium

For Debian users, libsodium is available via apt:

sudo apt-get install libsodium-dev

ruby_home

Add this line to your application's Gemfile:

gem 'ruby_home'

And then execute:

$ bundle

Or install it yourself with:

$ gem install ruby_home

Basic usage

Create a fan with an on/off switch:

require 'ruby_home'

accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
fan = RubyHome::ServiceFactory.create(:fan)

fan.on.after_update do |updated_value|
  if updated_value
    puts "Fan switched on"
  else
    puts "Fan switched off"
  end
end

RubyHome.run

Examples

The following example services are available:

Sensors

Controlables

Configuration

The configuration options can be set by using the configure helper:

RubyHome.configure do |c|
  c.discovery_name = 'My Home'
end

The following is the full list of available configuration options:

Method Description Default Example Type
discovery_name The user-visible name of the accessory "RubyHome" "My Home" String
model_name The model name of the accessory "RubyHome" "Device1,1" String
password Used for pairing, must conform to the format XXX-XX-XXX where each X is a 0-9 digit and dashes are required Randomly generated "101-48-005" String
host The hostname or IP address of the interface to listen on "0.0.0.0" "192.168.0.2" String
port The port that should be used when starting the built-in web server 4567 8080 Integer
category_identifier Indicates the category that best describes the primary function of the accessory. :bridge :fan Symbol

Customization

RubyHome tries to provide sane defaults for all services. Customization of any of the options is possible.

require 'ruby_home'

accessory_information = RubyHome::ServiceFactory.create(:accessory_information,
  firmware_revision: '4.3.18421',
  manufacturer: 'Fake Company',
  model: 'BSB001',
  name: 'Kickass fan bridge',
  serial_number: 'AB1-UK-A123456',
  category_identifier: :fan
)

fan = RubyHome::ServiceFactory.create(:fan,
  on: false,
  rotation_speed: 50,
  rotation_direction: 1,
  firmware_revision: '105.0.21169',
  manufacturer: 'Fake Company',
  model: 'LWB006',
  name: 'Kickass fan',
  serial_number: '123-UK-A12345'
)

fan.on.after_update do |updated_value|
  if updated_value
    puts "Fan switched on"
  else
    puts "Fan switched off"
  end
end

RubyHome.run

Updating a characteristics value

If you have a service with characteristics that can be changed outside of Ruby Home, you'll want to keep Ruby Home in sync with these modifications. Otherwise, the characteristics current value won't correspond with reality. The simplest way to do this is a background job that periodically polls the devices current status and updates the corresponding characteristics value if it's changed.

Given a fan which can be switched on / off with a remote control, which has a JSON API endpoint at http://example.org/fan_status.json that returns its current status { "on": true } or { "on": false }, we can spawn a thread that keeps polling the fans current status and if it's changed update our fan service "on" characteristic.

require 'json'
require 'open-uri'
require 'ruby_home'

fan = RubyHome::ServiceFactory.create(:fan)

Thread.new do
  def fetch_fan_status
    json = JSON.load(open("http://example.org/fan_status.json"))
    json["on"]
  end

  loop do
    sleep 10 # seconds

    current_fan_status = fetch_fan_status

    unless fan.on == current_fan_status
      fan.on = current_fan_status
    end
  end
end

RubyHome.run

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/karlentwistle/ruby_home.

ruby_home's People

Contributors

cannikin avatar dependabot[bot] avatar depfu[bot] avatar johndbritton avatar karlentwistle avatar lewispb avatar tenderlove avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ruby_home's Issues

New release for new services?

Trying to use the Valve service but it's values in the services.yml config file don't exist in the latest release, but they are there in master. Any plan to push a version update with the latest? Thanks!

How to add it to Home App on iOS

While doing some initial testing I realized that I don't have a code to add the accessory to the Home app on iOS. I used your sample code to create a fan then broadcast, but when trying to add the accessory there was no code.

Am I missing something?

HTTP Response error on versions 0.1.16 and 0.1.15

When trying to run the fan example, I get the following error on 0.1.16 and 0.1.15:

ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home.rb:32:in `block in start'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:19:in `run'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:19:in `loop'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:20:in `block in run'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:20:in `select'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:20:in `block (2 levels) in run'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:31:in `block in accept'
ruby/gems/2.5.0/gems/ruby_home-0.1.16/lib/ruby_home/hap/server.rb:63:in `read'
ruby/2.5.0/webrick/httpresponse.rb:205:in `send_response'
ruby/2.5.0/webrick/httpresponse.rb:214:in `rescue in send_response': undefined method `error' for nil:NilClass (NoMethodError)

This error message appears immediately when I tap "Add Anyway" (or something similar) on my phone after selecting the RubyHome bridge, before I can enter the code. If I revert to 0.1.14, the fan example works, as well as my custom scripts.

I'm on:
mac OS 10.13.6
ruby 2.5.0p0
libsodium 1.0.16

When going from 0.1.16 -> 0.1.14, I noticed the following bundler output:
Using oj 3.7.1 (was 3.7.4)
Using ruby_home 0.1.14 (was 0.1.16)

If, after adding a device on my phone, I upgrade to 0.1.16, I get the same error, this time immediately upon running the script. Back down to 0.1.14 and it works again. If there's anything further I can do to help diagnose, let me know.

define room for service

when creating a service the default room is selected. The services need to be manually moved to the correct room in the Home app.
It should be possible to define a room while creating a service.

Accessory doesn't send events to controller

Accessory Sends Events to Controller

The accessory should support delivering notifications by sending an event message, which is an unsolicited HTTP response, over the TCP connection established by the controller. An event message has the same format as an HTTP response, but uses a protocol version of EVENT/1.0. Event messages must never interrupt a response that is already being sent. A response message must also never interrupt an event message. Either of these violations would result in the controller receiving a corrupt message. Event messages do not receive an HTTP response from the controller.

For example when the value of the "current temperature" value changes, the accessory sends the following unsolicited message to the controller:

EVENT/1.0 200 OK
Content-Type: application/hap+json
Content-Length: <length>
{
  "characteristics" : [
    {
      "aid" : 1,
      "iid" : 4,
      "value" : 23.0
    }
  ]
}

Allow customising the bridge name

It'd be neat to be able to change the name of the device (bridge) that appears when you first try to pair, which is I think defined here. Perhaps it could be given as an argument to RubyHome.run?

Television Accessory showing incorrect icon

@karlentwistle Thanks for releasing the new version of the gem with the Television functionality. I got it installed and I am able to create an accessory, a television service, a speaker service, a few input services and link them all together.

They show up in the Home app and I can control volume and send button presses from the Remote app as well.

The only thing I can't get to work is to show the accessory as a TV in the Home app.

I've tried doing

RubyHome.configure do |c|
   c.discovery_name = 'Television'
   c.category_identifier = :television
 end

per the example, but this seems to operate on the Bridge, not the accessory. When I have this configuration, I see a TV icon when adding the bridge to the Home app, but after the accessory is added it displays a house icon instead of a TV.

Any ideas what I'm doing wrong?

Can't use services other than Fan

Hi,

I got the basic fan example working properly and then tried changing the fan to a garage door opener with:

door = RubyHome::AccessoryFactory.create(:garage_door_opener)

door.characteristic(:target_door_state).on(:updated) do |new_value|
  puts new_value.inspect
end

I deleted the bridge from my phone, and the YAML file from my working directory, before running the script again. The bridge shows in the Home app, but after entering the code, I get the error message:

Couldn't add RubyHome
Home couldn't connect to this accessory.

If, instead of replacing the fan with a garage door opener, I add a second fan to the example, both fans show up and work properly in the Home app.

I'm using ruby 2.5.0p0 on OS X 10.11.6 (El Capitan) and iOS 11.4.1 if that helps. Thanks.

What's the use of accessory information in the examples?

I mean this line:

accessory_information = RubyHome::ServiceFactory.create(:accessory_information)

What's it supposed to do? It's not really used anywhere else in any of the examples, and if I comment it in my own sensor implementation it doesn't really change anything.

Also, is there any other way to get to which service has which characteristics available other than doing sensor = RubyHome::ServiceFactory.create(:temperature_sensor) and then calling sensor.characteristics and going through it?

Running within Docker

It is possible to run ruby_home on Debian within Docker, but if you're running Docker on macOS you're likely to have problems.

ruby_home depends on dnssd which in turn depends on dbus. From what I can tell dbus is not enabled by default in Docker containers. The only workaround I could find was to connect the container to the host machine's dbus by mounting two volumes to the Docker container and running the container on a Linux host machine.

I was not able to get this to run in a Docker container running on a macOS host.

I also dropped a note upstream on the dnssd gem about this: tenderlove/dnssd#26

Default Room unavailable

When first pairing why does the bridge / accessory information always display with unavailable.

Specifically, what is the amber exclamation mark about.

Seems like a bug but could just be part of Home Kit. Would be good to investigate the behaviour with an official accessory and compare.

IOS 18

Do you think you will be implementing the new HomeKit accessory types in IOS 18. Specifically the vacuum and the energy consumption ?

Thanks
Eric Smith

OpenBSD misses dns_sd.h

This projects is awesome.
Until now i've used it on an old mac mini.
Now i would like to move everything on my OpenBSD home server.

It misses dns-sd, I'm getting the following error during install:

checking for dns_sd.h... no

I've already searched for an OpenBSD port of FreeBSD's net/avahi-libdns without luck.
Also, on OpenBSD there's not a port of Debian's libavahi-compat-libdnssd-dev

Do you know a workaround for this?

BTW many many thx for putting your efforts in building this thing, i saw your talk from Sheffield Ruby 18 and felt astonished by your hard work!

New gem version

Hi,

Is it possible that you can push a new version of you gem? I would like to use some of the changes you made.

Best regards,
Andreas

Error running sample accessory

I'm trying to get up and running with ruby_home, but struggling to get off the ground. My iOS device is an iPhone X running iOS 12.0.1. I've run the bin/rubyhome script, and see this output:

$ bin/rubyhome                              
Please enter this code with your HomeKit app on your iOS device to pair with RubyHome
                       
    ┌────────────┐     
    │ 150-11-185 │    
    └────────────┘     
                       
Listening on 0.0.0.0:4567

At this point, I tap to add a new HomeKit accessory on my iPhone, and see "RubyHome", so I add that and give the code above. This is the terminal output after that:

*** 192.168.0.49:60726 connected
[2018-11-06 15:21:55] INFO  WEBrick 1.4.2
[2018-11-06 15:21:55] INFO  ruby 2.5.1 (2018-03-29) [x86_64-darwin17]
192.168.0.49 - - [06/Nov/2018:15:21:55 +0000] "POST /pair-setup HTTP/1.1" 200 409 0.0915
192.168.0.49 - - [06/Nov/2018:15:22:01 +0000] "POST /pair-setup HTTP/1.1" 200 69 0.0442
192.168.0.49 - - [06/Nov/2018:15:22:01 +0000] "POST /pair-setup HTTP/1.1" 200 140 0.0036
*** 192.168.0.49:60726 disconnected
*** 192.168.0.49:60727 connected
192.168.0.49 - - [06/Nov/2018:15:22:02 +0000] "POST /pair-verify HTTP/1.1" 200 140 0.0047
192.168.0.49 - - [06/Nov/2018:15:22:02 +0000] "POST /pair-verify HTTP/1.1" 200 3 0.0012
- - - [06/Nov/2018:15:22:02 +0000] "GET /accessories HTTP/1.1" 200 2138 0.0040
E, [2018-11-06T15:22:02.454241 #56017] ERROR -- : undefined method `write' for "":String (NoMethodError)
/Users/james/.rubies/ruby-2.5.1/lib/ruby/2.5.0/webrick/httpresponse.rb:298:in `send_header'
/Users/james/.rubies/ruby-2.5.1/lib/ruby/2.5.0/webrick/httpresponse.rb:210:in `send_response'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/hap_response.rb:14:in `send_response'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:62:in `read'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:33:in `block in accept'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:21:in `block (2 levels) in run'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:21:in `select'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:21:in `block in run'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:20:in `loop'
/Users/james/Code/experiments/ruby_home/lib/ruby_home/hap/server.rb:20:in `run'
/Users/james/Code/experiments/ruby_home/lib/ruby_home.rb:32:in `block in start'
*** 192.168.0.49:60727 disconnected

On the phone it shows an error message: "Couldn't add RubyHome - Home couldn't connect to this accessory".

I've tried the other examples from the README, and get the same results. I'd really love to get this working -- anything I can do to help debug it, please let me know.

Example for color temperature

Hi there!
I am trying to read color temperature from a light bulb in Ruby Home. I tried doing it the same way as accessing hue and brightness in the example - am I doing something wrong?

accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
lightbulb = RubyHome::ServiceFactory.create(:lightbulb,
  on: true,
  name: "lightbulb",
  brightness: 100,
  color_temperature: 100,
)

lightbulb.color_temperature.after_update do |c|
  puts "lightbulb color temp is at #{c}"
end

RubyHome.run

But lightbulb.color_temperature does not exist (undefined method). Any ideas? Or does this only support reading it as color (hue, saturation and brightness)?

Thanks so much!

Is there a way to update a characteristic value without having it pass through the after_update chain?

I have a Z-Wave service running on my network, and I'm using ruby_home to bridge that to HomeKit.

To keep things in sync, I poll that z-wave service to get the current status of the various components in my house, and then update that value in ruby_home.

The problem is that sometimes the z-wave service can take a few minutes to update the value properly. So when I poll the z-wave service to the current value, then set that value via ruby_home, a command is sent back to the z-wave service, and the device gets updated, which sometimes resets the value of that device.

For example:

Bedroom light is at 100%
Open Home app on my iPhone, set Bedroom light to 50%
Command goes Home App -> Ruby Home -> Wave, and the light goes to 50%
However, the stupid z-wave service doesn't update itself immediately.
So now, my polling tool checks ZWave, which reports back that the light is still 100%
So then the polling tool updates the value to 100% in Ruby_Home, which then sends the command to that device to update to 100%, and now the light in the bedroom just went from 50% back to 100%.

What I want to do is only update the characteristic value in ruby_home/homekit, without triggering the full on_update chain.

Currently I do this:

@bridged_devices[zway_switch.id].on.value = current_status

But doing that always calls the after_update hook.

How can I set that value without calling the after_update hook?

Do I just need to use value_object.value= instead ?

Depfu Error: Found both *.gemspec and Gemfile.lock

Hello,

We've tried to activate or update your repository on Depfu and found something odd:

Your repo contains both a *.gemspec file and a Gemfile.lock.

Depfu can't really handle that right now, unfortunately, and it's also not best practice:

If your repo contains a *.gemspec that usually means it is meant to be used as a Gem, or put differently, a library. Locking dependencies on a library (via Gemfile.lock) doesn't really make sense, especially since the Gemfile.lock can't and won't be honored when building and installing the gem.

Instead, you should declare your dependencies as specifically as needed (but as loose as possible) in the *.gemspec and add the Gemfile.lock to your .gitignore.

By checking in the Gemfile.lock, you will not only break Depfu (which we might fix at some point, maybe), but you will also keep your CI from testing against real life sets of dependencies.


This is an automated issue by Depfu. You're getting it because someone configured Depfu to automatically update dependencies on this project.

Document more accessories

It would be useful to expand the README to show how to create more accessories than just the fan example.

Unable to pair ("setup code is incorrect")

Hi there!
I seem to be unable to add RubyHome to HomeKit (iOS 12.1.4, RubyHome running on Debian 9.8, Ruby 2.4.0), it says the code is incorrect (though I'm pretty sure i haven't mistyped it a hundred times). Pairing with HomeBridge works though, so I think the iOS-Devices are fine. I've tried resetting everything several times by deleting the yml files, but the new codes didn't work either.

I've looked at it - this check fails. The values look something like @M="af70fee65c32f5ccffd292e394a23bfccba43463fd9c481b96c6a6b7ecf3ffaa95ea6f06eb2349e5721ca7a7f0ee9042305d139f3edceab077d5ef9eb4137465"
client_M="\xF8\x00\x00\x8C\r\x7F\x00\x00\xA0H\x02\x8C\r\x7F\x00\x00a9d23346f1e4f698b01240ad830cf029d5d57fc79f1b1fc5e2c40862dfb3828fd2c58aa80f678a45a7f4d78b9c4ac33fec5546f2a10430a3"

I don't really know anything about SRP...
Any ideas? Thanks for your help!

unable to set Typ of Contact Sensor

in Homekit there are different types of contact sensors available, e.g. door or window.
Setting the typ should be possible when creating services.

Change maximum/minimum/step values of a numeric characteristic?

I'm implementing a split AC unit with no heater, starting from the included heater/cooler example. Removing the unneeded characteristics from the ServiceFactory call works fine, and I can prevent the "Heat" option from showing up with the following code, inserted just after it:

heater_cooler.characteristics.each do |c|
  if c.name == :target_heater_cooler_state
    c.constraints["ValidValues"].delete("1")
  end
end

I also want to limit the temperature between 17 and 31C in 1C steps, but the same strategy doesn't work there:

heater_cooler.characteristics.each do |c|
  if c.name == :cooling_threshold_temperature
    c.constraints["MaximumValue"] = 31
    c.constraints["MinimumValue"] = 17
    c.constraints["StepValue"] = 1
  end
end

The slider on my phone still shows 10 to 35C in 0.5C steps. Any ideas? Thanks.

TV device

Hi,

I've noticed that HomeBridge has a "TV" device defined (via a plugin). Any plans to do that for RubyHome? Can I help to add it if not?

Thank you!
Matt

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.