Layout for garbage_collection sensor

Ok, one last thing so far;: how can i add a schedule only with dedicated dates and without any schedule like “weekly”?

/ Ralf

@bruxy70: maybe you can help?
Thanks a lot in advance!

Hi. The configuration of this card is at the bottom of readme: https://github.com/bruxy70/Garbage-Collection/blob/development/README.md#icon-view-glance

Hello, quick question.

Im trying to set this up to give me a reminder of credit card payment due dates (same day each month)

I can’t get the sensors to populate. Any suggestions?

  - name: Walmart
    frequency: "monthly"
    verbose_state: true
    verbose_format: 'on {date}, in {days} days'
    first_date: '2020-01-12'

Thanks!

Hi.

This configuration will not work. I suggest using an annual frequency on 01/12, and then include the other 11 dates manually. See here

The whole integration has been really set around an event occurring at a given day of the week. So the monthly is meant to be used like - “each 1st Sunday of a month”. Which is quite common for what it was supposed to do originally.

What I did not realize was, people, started using it for scheduling all kinds of other things, for which I’d use simple integration with google calendar - like birthdays.

So I added the annual frequency to support that. But I did not yet add a recurring event on a given date every x months or so. Will put it on the list.

Since short, the component is not working as before. I’ve put a copy of the log error here https://pastebin.com/zD1JR8uQ
Looks like it’s not picking up the date and time correctly anymore.

good morning,
do you know how to set the verbose_format values in french?

Hi amaximus

I am new to HA. I have installed the Garbage Collection Integration via HACS. I have my sensors now created. One is sensor.rubbish another is sensor.mixed_recycling. Both work and I can see there is currently a state of 2 as they are over 2 days away. So I think all is OK with the integration. I then installed via HACS your custom card. This appears to have correctly installed and I can see the resources in Lovelace.

I want to use the standard cards you have created. I have tried using the .yaml on your page but the message I get when creating a manual card is No visual editor available for: custom:garbage-collection-card. It also says Please define an entity. Worse still when I hit save it stays red and doesn’t work. Below is my card .yaml.

Hoping you can help? Thanks in advance!!

type: 'custom:garbage-collection-card'
cards:
  - type: 'custom:garbage-collection-card'
    entity: sensor.rubbish
    icon_size: 35px
    icon_color: green
    hide_date: true
  - type: 'custom:garbage-collection-card'
    entity: sensor.mixed_recycling
    hide_before: 4
    icon_color: '#0561ba'

hello do you know how to configure in french especially for the remaining time

I’m not sure how configurating via UI works. Using the yaml mode your card config seems correct. Please double-check the resource dwfinition for the card. In yaml mode installed via HACS it should point to /local/community/garbage-collection-card/garbage-collection-card.js

The card itself supports other languages only for today and tomorrow (remaining time<2). For more complex output you might need to try verbose_format with verbose_state=true wheb defining the sensor.

Okay, thanks for the hint. I didn’t know.
Thank you

Hi I am sorry I do not understand your reply. This is my resources. I have installed all via HACs. I am not a .yaml guy but I copied it out of the .yaml hoping it would help you.

Is there a step by step?

I get: Please define an entity and the card is red


class GarbageCollectionCard extends HTMLElement {

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  version() { return "0.2.0"; }

  _label(label, fallback = 'unknown') {
    const lang = this.myhass.selectedLanguage || this.myhass.language;
    const resources = this.myhass.resources[lang];
    return (resources && resources[label] ? resources[label] : fallback);
  }

  _getAttributes(hass, filter1) {
    var next_date = '';
    var days = '';
    var friendly_name = '';
    var icon = '';
    var alerted = '';
    var routeobjarray = [];

    function _filterName(stateObj, pattern) {
      let parts;
      let attr_id;
      let attribute;

      if (typeof (pattern) === "object") {
        parts = pattern["key"].split(".");
        attribute = pattern["key"];
      } else {
        parts = pattern.split(".");
        attribute = pattern;
      }
      attr_id = parts[2];

      if (attr_id.indexOf('*') === -1) {
        return stateObj == attribute;
      }
      const regEx = new RegExp(`^${attribute.replace(/\*/g, '.*')}$`, 'i');
      return stateObj.search(regEx) === 0;
    }
 
    var filters1 = new Array();
    filters1[0] = {key: "sensor." + filter1 + ".next_date"};
    filters1[1] = {key: "sensor." + filter1 + ".days"};
    filters1[2] = {key: "sensor." + filter1 + ".friendly_name"};
    filters1[3] = {key: "sensor." + filter1 + ".icon"};

    const attributes = new Map();
    filters1.forEach((filter) => {
      const filters = [];

      filters.push(stateObj => _filterName(stateObj, filter));

      Object.keys(hass.states).sort().forEach(key => {
        Object.keys(hass.states[key].attributes).sort().forEach(attr_key => {
          if (filters.every(filterFunc => filterFunc(`${key}.${attr_key}`))) {
            attributes.set(`${key}.${attr_key}`, {
              value: `${hass.states[key].attributes[attr_key]} ${filter.unit||''}`.trim(),
            });
          }  
        });
      });
    });

    var attr = Array.from(attributes.keys());
    attr.forEach(key => {
      var newkey = key.split('.')[2];

      switch (newkey) {
        case 'next_date':
          next_date=attributes.get(key).value.split('T')[0];
          break;
        case 'days':
          days=attributes.get(key).value;
          break;
        case 'friendly_name':
          friendly_name=attributes.get(key).value;
          break;
        case 'icon':
          icon=attributes.get(key).value;
          break;
        default:
          break;
      }
    });
    if ( days < 2 ) {
	alerted='alerted_1';
    }
    if ( days < 1 ) {
	alerted='alerted';
    }

    routeobjarray.push({
      friendly_name: friendly_name,
      next_date: next_date,
      days: days,
      icon: icon,
      alerted: alerted,
    });
    return Array.from(routeobjarray.values());
  }

  setConfig(config) {
    if (!config.entity) {
      throw new Error('Please define an entity');
    }
    config.filter

    const root = this.shadowRoot;
    if (root.lastChild) root.removeChild(root.lastChild);

    const cardConfig = Object.assign({}, config);

    const card = document.createElement('ha-card');
    const content = document.createElement('div');
    const style = document.createElement('style');
    let icon_size = config.icon_size;
    if (typeof icon_size === "undefined") icon_size="25px"
    let icon_color = config.icon_color;
    if (typeof icon_color === "undefined") icon_color="black"
    let due_color = config.due_color;
    if (typeof due_color === "undefined") due_color="red"
    let due_1_color = config.due_1_color;
    if (typeof due_1_color === "undefined") due_1_color=due_color
    let details_size = config.details_size;
    if (typeof details_size === "undefined") details_size="14px"
    let title_size = config.title_size;
    if (typeof title_size === "undefined") title_size="17px"

    style.textContent = `
      table {
        width: 100%;
        margin-left: auto;
        margin-right: auto;
      }
      td {
        font-size: 120%;
        text-align: left;
      }
      .tdicon {
        padding-left: 35px;
        width: 60px;
      }
      ha-icon {
        color: ${icon_color};
        --mdc-icon-size: ${icon_size};
      }
      .alerted {
        color: ${due_color};
      }
      .alerted_1 {
        color: ${due_1_color};
      }
      .details {
        font-size: ${details_size}
      }
      .emp {
        font-size: 130%;
      }
      .name {
        text-align: left;
        font-size: ${title_size}
      }
    `;
    content.innerHTML = `
      <table>
        <tbody id='attributes'>
        </tbody>
      </table>
    `;
    card.appendChild(style);
    card.appendChild(content);
    root.appendChild(card)
    this._config = cardConfig;
  }

  _updateContent(element, attributes, hdate, hdays, hcard) {
    element.innerHTML = `
      ${attributes.map((attribute) => `
        <tr>
          <td rowspan=2 class="tdicon"><ha-icon icon="${attribute.icon}" class="${attribute.alerted}"></td>
          <td class="name"><span class="emp">${attribute.friendly_name}</span></td>
        </tr>
        <tr>
          <td class="details">
            ${hdate === false ? `${attribute.next_date}` : ''}
            ${hdays === false ? " " + `${this._label('ui.components.relative_time.future.In', 'in')}` +
                                " " + `${attribute.days}` + " " + `${this._label('ui.duration.days', 'days')}` : '' }
          </td>
        </tr>
      `).join('')}
    `;

    this.style.display = hcard?"none":"block";
  }

  set hass(hass) {
    const config = this._config;
    const root = this.shadowRoot;
    this.myhass = hass;

    let hide_date = false;
    if (typeof config.hide_date != "undefined") hide_date=config.hide_date
    let hide_days = false;
    if (typeof config.hide_days != "undefined") hide_days=config.hide_days
    let hide_card = false;
    let hide_before = -1;
    if (typeof config.hide_before != "undefined") hide_before=config.hide_before

    let attributes = this._getAttributes(hass, config.entity.split(".")[1]);
    if (hide_before>-1) {
      let iDays = parseInt(attributes[0].days,10);
      if (iDays > hide_before) {
        hide_card = true;
      }
    }

    this._stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
    if ( isNaN(this._stateObj.state) ) {
      hide_days = true;
      hide_date = false;

      const translationLocal = "/local/community/garbage-collection-card/" + hass.language + ".json";
      var rawFile = new XMLHttpRequest();
   // rawFile.responseType = 'json';
      rawFile.overrideMimeType("application/json");
      rawFile.open("GET", translationLocal, false);
      rawFile.send(null);
      if ( rawFile.status != 200 ) {
        attributes[0].next_date = this._stateObj.state;
      } else {
        if ( attributes[0].days > 1 ) {
          attributes[0].next_date = this._stateObj.state;
        } else {
          var translationJSONobj = JSON.parse(rawFile.responseText);
          if ( typeof translationJSONobj != "undefined" ) {
            if ( typeof translationJSONobj.state[this._stateObj.state] != "undefined" ) {
              attributes[0].next_date = translationJSONobj.state[this._stateObj.state];
            } else {
              attributes[0].next_date = this._stateObj.state;
            }
          } else {
            attributes[0].next_date = this._stateObj.state;
          }
        }
      }
    }

    this._updateContent(root.getElementById('attributes'), attributes, hide_date, hide_days, hide_card );
  }

  getCardSize() {
    return 1;
  }

}

customElements.define('garbage-collection-card', GarbageCollectionCard);

In your HASS configuration file you have to define the resources section to point to the locaction of the card as per the Readme (with some exception). In yaml mode the card is located in www/community/garbage-collection-card directory so you have to specify local/community/garbage-collection-card/garbage-collection-card.js in the resources section.

Hi Atticus

So I have put the following in my configuration.yaml file

resources:
  - type: 'local/community/garbage-collection-card/garbage-collection-card.js'
    cards:
      - type: custom:garbage-collection-card
        entity: sensor.glass_recycling
        icon_size: 35px
        icon_color: green
        hide_date: true
      - type: custom:garbage-collection-card
        entity: sensor.rubbish
        hide_before: 4
        icon_color: '#0561ba'

When I check the configuration I get " Configuration invalidCHECK CONFIGURATION

Component error: resources - Integration ‘resources’ not found."

I am sorry I have read your messages and read the read me, promise. I am just missing something here.

The resource definition should have the following format:

- {type: js, url: 'local/community/garbage-collection-card/garbage-collection-card.js'}

Thanks so much for the reply :slight_smile: It is appreciated. I am sorry this is taking so long!
OK so below this is what I put in my configuration.yaml file. When I check the config it says
Error loading /config/configuration.yaml: while parsing a block collection
in “/config/configuration.yaml”, line 519, column 3
expected , but found ‘’
in “/config/configuration.yaml”, line 520, column 5

resources:
  - {type: js, url: 'local/community/garbage-collection-card/garbage-collection-card.js'}
    cards:
      - type: custom:garbage-collection-card
        entity: sensor.glass_recycling
        icon_size: 35px
        icon_color: green
        hide_date: true
      - type: custom:garbage-collection-card
        entity: sensor.rubbish
        hide_before: 4
        icon_color: '#0561ba'

Sorry I missed the first slash:

  • {type: js, url: ‘/local/community/garbage-collection-card/garbage-collection-card.js’}

Nope, sorry. Pasted that in and still get:

Error loading /config/configuration.yaml: while parsing a block collection
in “/config/configuration.yaml”, line 518, column 3
expected , but found ‘’
in “/config/configuration.yaml”, line 519, column 5

resources:
  - {type: js, url: ‘/local/community/garbage-collection-card/garbage-collection-card.js’}
    cards:
      - type: custom:garbage-collection-card
        entity: sensor.glass_recycling
        icon_size: 35px
        icon_color: green
        hide_date: true
      - type: custom:garbage-collection-card
        entity: sensor.rubbish
        hide_before: 4
        icon_color: '#0561ba'

Please note that the cards part should go into ui-lovelace.yaml, not the configuration.yaml.