Navigation on sensor widget

Hi,

I searched all over the documentation and the forum but I can’t find how to do this. So I guess it’s not implemented. However I think it must be very easy for the developers to add this.

I have a couple of sensors that just show a value. I have navigation widgets that take you to a detailed dashboard. Why not combine both? Why can’t I click on a sensor widget to take you to a detailed dashboard?
I don’t like that the navigation widgets take up so much place on the dashboard because a clickable sensor could do the same thing. The sensor or widget only needs a target dashboard parameter.

  • My car presence sensor (home/not_home) could link to a dashboard which has all the sensors of the car. It’s over 20 of them!
  • For example I want to show a small camera widget with a live view but i want to be able to click it to watch it full screen(8x6).
  • The same goes for the weather widget. It could point to a dashboard with a 7 day forecast and a weather map.
  • I have a sensor that shows a gauge of the current download speed in kbytes/sec. It could take you to a dashboard with a list of all the connected devices so you can see what’s on or off.

it isnt possible at the moment, but it is on our to do list when we start working on the dashboard again.
first there will be a beta relase from AD 4.0 which has a lot off changes for the apps part, after that we will make a lot of changes to the dashboard.

if you find it hard to wait for it, you can create your own custom widgets. (i think it must be very easy to do that for you, with the docs that are there showing you how :wink: )

I would love to create a custom clickable sensor widget but I have no idea how to start or where to place the files. I can’t find any simple example.

i reacted that way, because you yourselve stated that it must be very easy :wink:

here is the docs that show you how to create custom widgets:

https://appdaemon.readthedocs.io/en/latest/WIDGETDEV.html

in short:

  • create a dir custom_widgets in your config area
  • copy an existing widget to it
  • change the parts that need to be changed (at least the nameparts) on all places needed
  • add the stuff you want.

do that for all widgets (because you want navigate for all of them)

like you said, it isnt hard, but very time consuming.

  • copy an existing widget to it

From where? I access Hassio via samba. I can’t find any existing widgets in the folders.

widgets are in the appdaemon directory that is in the python environment.
its possible that hassio doesnt give you access to that.

you can also find them on the appdaemon github.


there you can download them.

dont forget to make sure the files get the right owner and the right filerights, or they wont work at all.

From the link above I downloaded the navigation widget and the weather widget.
I merged the two and I have now a (1x1) weather widget that goes to the weather dashboard when clicked upon.
The only thing that I can’t get to work is the spinning icon when you press it.
The js code can use some cleanup too.
Can someone help me please?

custom_widgets/baseweathernav/baseweathernav.yaml

.widget-baseweathernav-{{id}} .toggle-area {
	z-index: 10;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}

.widget-baseweathernav-{{id}} .title {
	position: absolute;
	top: 5px;
	width: 100%;
}

.widget-baseweathernav-{{id}} .state_text {
	position: absolute;
	bottom: -3px;
	width: 100%;
}

.widget-baseweathernav-{{id}} .climacon {
	margin-top: 15px;
	font-family: "Climacons-Font";
	font-size: 70px;
}

.widget-baseweathernav-{{id}} .rain:before{
    content: "\e009";
}

.widget-baseweathernav-{{id}} .snow:before{
    content: "\e036";
}

.widget-baseweathernav-{{id}} .sleet:before{
    content: "\e003";
}

.widget-baseweathernav-{{id}} .wind:before{
    content: "\e021";
}

.widget-baseweathernav-{{id}} .fog:before{
    content: "\e01b";
}

.widget-baseweathernav-{{id}} .cloudy:before{
    content: "\e000";
}

.widget-baseweathernav-{{id}} .clear-day:before{
    content: "\e028";
}

.widget-baseweathernav-{{id}} .clear-night:before{
    content: "\e02d";
}

.widget-baseweathernav-{{id}} .partly-cloudy-day:before{
    content: "\e001";
}

.widget-baseweathernav-{{id}} .partly-cloudy-night:before{
    content: "\e002";
}

custom_widgets/baseweathernav/baseweathernav.html

<span class="toggle-area" id="switch"></span>
<h1 class="title" data-bind="text: title, attr:{ style: title_style}"></h1>
<p class="climacon" data-bind="css: icon"></p>
<h1 class="state_text">
	<span data-bind="text: temperature"></span>&nbsp;<span data-bind="html: unit, attr: {style: unit_style}"></span>
</h1>

custom_widgets/baseweathernav/baseweathernav.js

function baseweathernav(widget_id, url, skin, parameters)
{
    // Will be using "self" throughout for the various flavors of "this"
    // so for consistency ...

    self = this;

    // Initialization

    self.widget_id = widget_id;

    // Parameters may come in useful later on

    self.parameters = parameters;
    self.skin = skin;

    self.OnButtonClick = OnButtonClick

    var callbacks =
        [
            {"selector": '#' + widget_id + ' > span', "action": "click","callback": self.OnButtonClick},
        ]

    // Define callbacks for entities - this model allows a widget to monitor multiple entities if needed
    // Initial will be called when the dashboard loads and state has been gathered for the entity
    // Update will be called every time an update occurs for that entity

    self.OnStateAvailable = OnStateAvailable;
    self.OnStateUpdate = OnStateUpdate;

    // Map will be used to know what field are we going to update from what sensor
    self.entities_map = {}

    var monitored_entities = []

    var entities = $.extend({}, parameters.entities, parameters.sensors);
    for (var key in entities)
    {
        var entity = entities[key]
        if (entity != '')
        {
            monitored_entities.push({
                "entity": entity, "initial": self.OnStateAvailable, "update": self.OnStateUpdate
            })
            self.entities_map[entity] = key
        }
    }

    // Finally, call the parent constructor to get things moving

    WidgetBase.call(self, widget_id, url, skin, parameters, monitored_entities, callbacks);

    // Function Definitions

    // The OnStateAvailable function will be called when
    // self.state[<entity>] has valid information for the requested entity
    // state is the initial state
    // Methods

    function OnStateUpdate(self, state)
    {
        set_view(self, state)
    }

    function OnStateAvailable(self, state)
    {
        field = self.entities_map[state.entity_id] 
        if (field == 'temperature')
        {
            self.set_field(self, "unit", state.attributes.unit_of_measurement)
        }
        set_view(self, state)
    }

    function set_view(self, state)
    {
        field = self.entities_map[state.entity_id] 
//        if (field)
 //       {
            if (field == 'precip_type')
            {
                self.set_field(self, "precip_type_icon", self.parameters.icons[state.state])
            }
            self.set_field(self, field, state.state)
//        }
    }
    
    if ("command" in parameters)
    {
        command = parameters.command
    }
    else if ("url" in parameters || "dashboard" in parameters)
    {
        if ("url" in parameters)
        {
            url = parameters.url
        }
        else
        {
            url = "/" + parameters.dashboard
        }
        var i = 0;

        if ("args" in parameters)
        {
            
            url = url + "?";
            
            for (var key in parameters.args)
            {
                if (i != 0)
                {
                    url = url + "&"
                }
                url = url + key + "=" + parameters.args[key];
                i++
            }
        }
        if ("skin" in parameters)
        {
            theskin = parameters.skin
        }
        else
        {
            theskin = skin
        }

        if (i == 0)
        {
            url = url + "?skin=" + theskin;
            i++
        }
        else
        {
            url = url + "&skin=" + theskin;
            i++
        }

        if ("sticky" in parameters)
        {
            if (i == 0)
            {
                url = url + "?sticky=" + parameters.sticky;
                i++
            }
            else
            {
                url = url + "&sticky=" + parameters.sticky;
                i++
            }
        }

        if ("return" in parameters)
        {
            if (i == 0)
            {
                url = url + "?return=" + parameters.return;
                i++
            }
            else
            {
                url = url + "&return=" + parameters.return;
                i++
            }
        }

        if ("timeout" in parameters)
        {
            if (i == 0)
            {
                url = url + "?timeout=" + parameters.timeout;
                i++
            }
            else
            {
                url = url + "&timeout=" + parameters.timeout;
                i++
            }
        }
        command = "window.location.href = '" + url + "'"
    }

    //self.set_icon(self, "icon", self.icons.icon_inactive);
    //self.set_field(self, "icon_style", self.css.icon_inactive_style);

    self.command = command;
    
    function OnButtonClick(self)
    {
        //self.set_icon(self, "icon", self.icons.icon_active);
        //self.set_field(self, "icon_style", self.css.icon_active_style);
        eval(self.command);
    }
}

custom_widgets/weathernav.yaml

widget_type: baseweathernav
fields:
  title: ""
  prefer_icons: 0
  unit: ""
  temperature: ""
  icon: ""
entities:
  icon: sensor.dark_sky_icon
  temperature: sensor.dark_sky_temperature
css: []
static_css:
  title_style: $weather_sub_style
  unit_style: $weather_unit_style
  main_style: $weather_main_style
  sub_style: $weather_sub_style
  sub_unit_style: $weather_sub_style
  widget_style: $weather_widget_style
icons:
  snow: mdi-snowflake
  rain: mdi-umbrella
  sleet: mdi-weather-snowy-rainy
  unknown: mdi-umbrella
static_icons: []

dashboards/menu.yaml

weatherbutton:
    widget_type: weathernav
    #title: Weather
    dashboard: Weather
    args:
      timeout: 60
      sticky: 1
      return: Overview
    sensors:
        icon: sensor.dark_sky_icon
        temperature: sensor.dark_sky_temperature
    title_style: "color: #FFFFFF"
    main_style: "color: white;"
    unit_style: "color: white;"
    widget_style: "background: rgba(211,84,0, 0.85);"

i wouldnt worry to much about how the js looks.
if it works it works.

in the near future it will be a default function anyway, so at that point you can remove your custom widget and use the default functions.

Can’t wait. If I don’t use clickable widgets I need two widgets for about everything.
I’m using HADashboard since two weeks and I already have 16 dashboards.
I just created a clickable gauge.
It shows my current download speed and when I click it, it takes me to the Network dashboard which shows info about my 3 NAS and 2 UPS and which devices are online/offline.
I love HADashboard!

2 Likes