Wall Mounted Dashboard (now known as HADashboard)

@aimc - Is there any reason (beyond you simply not needing or wanting) for not supporting all of the entity types that Home Assistant has? For example, binary_sensor or locks?

I’ve not spent much time (yet) looking at reverse engineering what you’ve done to see if I can add the features on my own. I probably don’t have the skills to make it work when I do spend the time though :smile: If I can figure it out I’ll certainly pass it on.

Right now I’m using a combination of scripts and the input_boolean entities to hack together the manipulation and display the states of all of my locks and door sensors. Works pretty good, but isn’t scalable nor does it work well when I restart Home Assistant… All of the input_boolean entities have a tendency to not accurately represent what they should.

Since I built this primarily for my own use, so far I have only implemented what I need. I don’t have any locks for instance so building a lock widget could be challenging! Hamotion does actually support binary sensors.

Awesome - Hamotion alone pulls a few hundred lines from my automation, input_boolean, and script files! I’ll poke around and see if I can figure out the locks.

1 Like

That would be great - let me know if you need anyone to test.

The original incarnation of this had support for locks - that should give you a head start as you should be able to re-use the widget, If you need any help with the backend piece, just let me know and we can work through it together - would be good to get locks working as I will be getting one or more at some stage.

This is great! I’ve modified those three files… I think. Can you point me in the direction of the backend pieces that need modified?

I added these lines in jobs/homeassistant.rb: (modeled after the garage lines I found in the file)

get '/homeassistant/lock' do
        response = ha_api("states/lock." + params["widgetId"], "get")
        return JSON.generate({"state" => response["state"]})
end

post '/homeassistant/lock' do
        entity_id = "lock." + params["widgetId"]
        command = "lock"
        if params["command"] == "unlock"
                command = "unlock"
        else
                command = "lock"
        end
        ha_api("services/lock/" + command, "post", {"entity_id" => entity_id})
        return respondWithSuccess()
end
1 Like

That should be enough to let you set the lock, and also get its status on a browser refresh, the final piece is to modify hapush.py to push the appropriate status updates back to the browser.

1 Like

Any idea what I’m doing wrong with the ‘halock’?

widgets/halock/halock.coffee

class Dashing.Halock extends Dashing.ClickableWidget
  constructor: ->
    super
    @queryState()

  @accessor 'state',
    get: -> @_state ? 'unlocked'
    set: (key, value) -> @_state = value

  @accessor 'icon',
    get: -> if @get('state') == 'unlocked' then 'unlock-alt' else 'lock'
    set: Batman.Property.defaultAccessor.set

  @accessor 'icon-style', ->
    if @get('state') == 'locked' then 'icon-locked' else 'icon-unlocked'

  toggleState: ->
    newState = if @get('state') == 'locked' then 'unlock' else 'lock'
    @set 'state', newState
    return newState

  queryState: ->
    $.get '/homeassistant/lock',
      widgetId: @get('id'),
      deviceType: 'lock',
      deviceId: @get('device')
      (data) =>
        json = JSON.parse data
        @set 'state', json.state

  postState: ->
    newState = @toggleState()
    $.post '/homeassistant/lock',
      deviceType: 'lock',
      deviceId: @get('device'),
      command: newState,
      (data) =>
        json = JSON.parse data
        if json.error != 0
          @toggleState()

  ready: ->

  onData: (data) ->

  onClick: (event) ->
    @postState()

widgets/halock/halock.scss

// ----------------------------------------------------------------------------
// Widget styles
// ----------------------------------------------------------------------------
.widget-halock {

  background-color: #444 !important;

  .title {
    color: #fff;
  }

  .icon-unlocked {
  	color: #ff00aa;
  }

  .icon-locked {
  	color: #fff;
  }

}

widgets/halock/halock.html

<h1 class="title" data-bind="title"></h1>

<h2 data-bind-class="icon-style"><i data-bind-class="icon | prepend 'fa fa-'"></i></h2>

jobs/homeassistant.rb

get '/homeassistant/lock' do
	response = ha_api("states/lock." + params["widgetId"], "get")
	return JSON.generate({"state" => response["state"]})
end

post '/homeassistant/lock' do
	entity_id = "lock." + params["widgetId"]
	command = "lock"
	if params["command"] == "unlock" 
		command = "unlock"
	else
		command = "lock"
	end
	ha_api("services/lock/" + command, "post", {"entity_id" => entity_id})
	return respondWithSuccess()
end

hapush/hapush.py

def dashboard_update(widget_id, type, state):
  
  try:
    .....
    elif type == "lock":
      values = {"state": state['state']}
      logger.info("lock." + widget_id + " -> " + state['state'])
      call_ha(widget_id, values)
       ......

 views = {
        "Hadevicetracker": "device_tracker",
        "Hagarage": "garage_door",
        "Halock": "lock",
        ......

Here is the log file and the error that I’m confident coincides with when I click the widget:

2016-07-08 22:36:18 - TypeError - no implicit conversion of nil into String:
	/var/opt/hadashboard/jobs/homeassistant.rb:66:in `+'
	/var/opt/hadashboard/jobs/homeassistant.rb:66:in `block in <top (required)>'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1611:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1611:in `block in compile!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:975:in `[]'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:975:in `block (3 levels) in route!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:994:in `route_eval'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:975:in `block (2 levels) in route!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1015:in `block in process_route'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1013:in `catch'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1013:in `process_route'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:973:in `block in route!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:972:in `each'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:972:in `route!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1085:in `block in dispatch!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `block in invoke'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `catch'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `invoke'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1082:in `dispatch!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:907:in `block in call!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `block in invoke'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `catch'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `invoke'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:907:in `call!'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:895:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb:18:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb:16:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb:18:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
	/var/lib/gems/2.1.0/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb:31:in `call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/logger.rb:15:in `call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/commonlogger.rb:33:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:219:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:212:in `call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/head.rb:11:in `call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/methodoverride.rb:21:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/show_exceptions.rb:25:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:182:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:2013:in `call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1487:in `block in call'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1787:in `synchronize'
	/var/lib/gems/2.1.0/gems/sinatra-1.4.7/lib/sinatra/base.rb:1487:in `call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/urlmap.rb:65:in `block in call'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/urlmap.rb:50:in `each'
	/var/lib/gems/2.1.0/gems/rack-1.5.5/lib/rack/urlmap.rb:50:in `call'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/connection.rb:86:in `block in pre_process'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/connection.rb:84:in `catch'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/connection.rb:84:in `pre_process'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/connection.rb:53:in `process'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/connection.rb:39:in `receive_data'
	/var/lib/gems/2.1.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run_machine'
	/var/lib/gems/2.1.0/gems/eventmachine-1.2.0.1/lib/eventmachine.rb:194:in `run'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/backends/base.rb:73:in `start'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/server.rb:162:in `start'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/controllers/controller.rb:87:in `start'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/runner.rb:200:in `run_command'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/lib/thin/runner.rb:156:in `run!'
	/var/lib/gems/2.1.0/gems/thin-1.6.4/bin/thin:6:in `<top (required)>'
	/usr/local/bin/thin:23:in `load'
	/usr/local/bin/thin:23:in `<top (required)>'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:63:in `load'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:63:in `kernel_load'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:24:in `run'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/cli.rb:304:in `exec'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/cli.rb:11:in `start'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/exe/bundle:27:in `block in <top (required)>'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/lib/bundler/friendly_errors.rb:98:in `with_friendly_errors'
	/var/lib/gems/2.1.0/gems/bundler-1.12.5/exe/bundle:19:in `<top (required)>'
	/usr/local/bin/bundle:23:in `load'
	/usr/local/bin/bundle:23:in `<main>'

And this is line 66 in homeassistant.rb:
response = ha_api("states/lock." + params["widgetId"], "get")

1 Like

Hi there - the problem is that in the post you aren’t passing through the widget ID (I changed the semantics a little from the original).

Try something like this:

postState: ->
    newState = @toggleState()
    $.post '/homeassistant/lock',
      widgetId: @get('id'),
      command: newState,
      (data) =>
        json = JSON.parse data
        if json.error != 0
          @toggleState()

For this, Hadevicetracker is a good example of how you want it to work.

Also, try something like this for the get:

  queryState: ->
    $.get '/homeassistant/lock',
      widgetId: @get('id'),
      (data) =>
        json = JSON.parse data
        @set 'state', json.state

You shouldn’t need to change anything else in the widget.

Also, the hapush code looks good.

1 Like

#SundayIsFunday

Let me know what you guys thing about the look!

1 Like

That dimmer looks VERY cool - do you have it working yet?

I do… Just tweaking some ascetics :slight_smile:

Hopefull have it up later today…

1 Like

Please share when you are ready :slight_smile:

All of a sudden started getting this error. I removed some items from main.erb. Syntax in the file still looks ok. Know what happened?

automate@aspire-automation:~$ cd /home/automate/hadashboard/hapush
automate@aspire-automation:~/hadashboard/hapush$ ./hapush.py hapush.cfg
2016-07-10 19:17:09,664 INFO Reading dashboard: /home/automate/hadashboard/dashboards/main.erb
Traceback (most recent call last):
  File "./hapush.py", line 319, in <module>
    main()
  File "./hapush.py", line 302, in main
    readDashboards()
  File "./hapush.py", line 220, in readDashboards
    readDash(file)
  File "./hapush.py", line 198, in readDash
    if not data_input in widgets["input_select"]:
KeyError: 'input_select'
automate@aspire-automation:~/hadashboard/hapush$

Can you post your main.erb please? I am guessing I made an unwarranted assumption that any dashboard has an input_select in it somewhere but I’d like to verify before I attempt a fix. If you wanted to test the assumption you could add an input_select and see if it fixes the problem.

http://pastebin.com/2WbK42dm

Also note I have a couple of .bak files in the directory if that makes a difference.

OK, so you have scripts that have the “data-input” tag - this should not be used unless you are tying the scripts to an input_select like in the example dashboard. If you remove them the error should disappear.

I will put in a fix for this in the next release however.

Regards,

Ok cool. Will fix when I get home and upload the dimmer widget.

I am looking to launch an Android app when clicking on a specific tile. Currently I am using a combination of tasker and auto remote. The tile has the “on click” attribute with the auto remote URL. Chrome opens the URL and tasker launches the app. Does anyone else have a more streamlined approach? I hate seeing chrome open to launch the app.

Usage:
I have harmony setup in home assistant and when clicking the harmony sensor tile on the dashboard, it opens the harmony app.

Hey Guys I just want to apologize for nu putting up the widget as yet. I found some bugs last minute and would like to work those out before uploading. Bear with me…

2 Likes