class XiaomiVacuumCard extends Polymer.Element { static get template() { return Polymer.html` [[name]] [[getValue('status')]] [[getValue('battery', ' %')]] [[getValue('mode')]] [[computeValue('main_brush')]] [[computeValue('side_brush')]] [[computeValue('filter')]] [[computeValue('sensor')]] `; } moreInfo() { this.fireEvent('hass-more-info'); } startVaccum() { this.callService(this._config.service.start); } pauseVacuum() { this.callService(this._config.service.pause); } stopVacuum() { this.callService(this._config.service.stop); } locateVacuum() { this.callService(this._config.service.locate); } returnVacuum() { this.callService(this._config.service.return); } cleanSpot() { this.callService(this._config.service.spot); } callService(service) { this._hass.callService('vacuum', service, {entity_id: this._config.entity}); } fireEvent(type, options = {}) { const event = new Event(type, { bubbles: options.bubbles || true, cancelable: options.cancelable || true, composed: options.composed || true, }); event.detail = {entityId: this._config.entity}; this.shadowRoot.dispatchEvent(event); return event; } getCardSize() { if (this.name && this.showButtons) return 5; if (this.name || this.showButtons) return 4; return 3; } setConfig(config) { const labels = { status: 'Status', battery: 'Battery', mode: 'Mode', main_brush: 'Main Brush', side_brush: 'Side Brush', filter: 'Filter', sensor: 'Sensor', hours: 'h', }; const services = { start: 'start', pause: 'pause', stop: 'stop', locate: 'locate', return: 'return_to_base', spot: 'clean_spot', }; const buttons = { start: true, pause: true, stop: true, spot: false, locate: true, return: true, }; const attributes = { status: 'status', battery: 'battery_level', mode: 'fan_speed', main_brush: 'main_brush_left', side_brush: 'side_brush_left', filter: 'filter_left', sensor: 'sensor_dirty_left', }; const vendors = { xiaomi: { image: '/local/img/vacuum.png', details: true, }, valetudo: { image: '/local/img/vacuum.png', details: true, attributes: { status: 'state', main_brush: 'mainBrush', side_brush: 'sideBrush', filter: 'filter', sensor: 'sensor', }, }, ecovacs: { image: '/local/img/vacuum_ecovacs.png', details: false, buttons: { stop: false, spot: true, }, service: { start: 'turn_on', pause: 'stop', stop: 'turn_off', }, }, deebot: { image: '/local/img/vacuum_ecovacs.png', details: true, service: { start: 'turn_on', pause: 'stop', stop: 'turn_off', }, attributes: { main_brush: 'component_main_brush', side_brush: 'component_side_brush', filter: 'component_filter', }, computeValue: v => Math.round(Number(v) / 100), } }; if (!config.entity) throw new Error('Please define an entity.'); if (config.entity.split('.')[0] !== 'vacuum') throw new Error('Please define a vacuum entity.'); if (config.vendor && !config.vendor in vendors) throw new Error('Please define a valid vendor.'); const vendor = vendors[config.vendor] || vendors.xiaomi; this.showDetails = vendor.details; this.showButtons = config.buttons !== false; config.service = Object.assign({}, services, vendor.service); config.buttons = Object.assign({}, buttons, vendor.buttons, config.buttons); config.attributes = Object.assign({}, attributes, vendor.attributes, config.attributes); config.labels = Object.assign({}, labels, config.labels); this.getValue = (field, unit = '') => { const value = (this.stateObj && config.attributes[field] in this.stateObj.attributes) ? this.stateObj.attributes[config.attributes[field]] + unit : (this._hass ? this._hass.localize('state.default.unavailable') : 'Unavailable'); return `${config.labels[field]}: ${value}`; }; this.computeValue = field => { if (this.stateObj && config.attributes[field] in this.stateObj.attributes) { const value = this.stateObj.attributes[config.attributes[field]]; return `${config.labels[field]}: ${vendor.computeValue ? vendor.computeValue(value) : value} ${config.labels.hours}`; } else { return `${config.labels[field]}: - `; } }; this.contentText = `color: ${config.image !== false ? 'white; text-shadow: 0 0 10px black;' : 'var(--primary-text-color)'}`; this.contentStyle = `padding: ${this.showButtons ? '16px 16px 4px' : '16px'}; ${this.contentText}`; this.backgroundImage = config.image !== false ? `background-image: url('${config.image || vendor.image}')` : ''; this._config = config; } set hass(hass) { this._hass = hass; if (hass && this._config) { this.stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null; if (this.stateObj) { this.name = this._config.name !== false && (this._config.name || this.stateObj.attributes.friendly_name); } } } } customElements.define('xiaomi-vacuum-card', XiaomiVacuumCard);