diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml new file mode 100644 index 0000000..e6790c4 --- /dev/null +++ b/.github/workflows/validate.yaml @@ -0,0 +1,18 @@ +name: Validate + +on: + push: + pull_request: + schedule: + - cron: "0 0 * * *" + +jobs: + validate: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v2" + - name: HACS validation + uses: "hacs/integration/action@master" + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CATEGORY: "plugin" diff --git a/DOCs/images/LiveCards.png b/DOCs/images/LiveCards.png new file mode 100644 index 0000000..cfdaca5 Binary files /dev/null and b/DOCs/images/LiveCards.png differ diff --git a/README.md b/README.md index 9239d3e..24e8352 100644 --- a/README.md +++ b/README.md @@ -2,43 +2,30 @@ ![Project Maintenance][maintenance-shield] +[![hacs_badge][hacs-shield]](https://github.com/custom-components/hacs) + [![License][license-shield]](LICENSE) [![GitHub Release][releases-shield]][releases] ![Release](https://github.com/ironsheep/lovelace-rpi-monitor-card/workflows/Release/badge.svg) -If you have a number of Raspberry Pis on your network then this might be the card you need to setup your Dashboard for monitoring all of you RPi's. - -## Where to get the sensor software - -Software supporting this card which sends data to Home Assistant from each of your Raspberry Pi's can be found at [RPi Reporter MQTT2HA Daemon](https://github.com/ironsheep/RPi-Reporter-MQTT2HA-Daemon).] +If you have a number of Raspberry Pis on your network then this might be the card you need to setup your Dashboard for monitoring all of you RPi's. Setup the sensor software on your RPi: See [RPi Reporter MQTT2HA Daemon](https://github.com/ironsheep/RPi-Reporter-MQTT2HA-Daemon). Then install this card to display the state of your RPi. ## About this card -This is a Lovelace card showing you the status of one of the Raspberry Pi's on your network. This card offers a choice of smaller 'glance' style card or the large 'details' card. You choose which you'd like for each of your RPi's. +This is a Lovelace card showing you the status of one of the Raspberry Pi's on your network. This card offers a choice of smaller 'glance' style card or the larger 'full' card. You choose which you'd like for each of your RPi's. -This card is currently in development. Our design goal is that the cards (glance, full) should look like this: (shown using 'Dark Orange' theme) +![Actual Card Layouts](./DOCs/images/LiveCards.png) -![Planned Card Layouts](./DOCs/images/DesignGoal.png) +Place one of these cards for each of your RPi's on your network (and install the sensor/daemon script on each RPi) and you can monitor your entire constellation of RPi's "at a glance"! ---- +-- If you like my work and/or this has helped you in some way then feel free to help me out for a couple of :coffee:'s or :pizza: slices! [![coffee](https://www.buymeacoffee.com/assets/img/custom_images/black_img.png)](https://www.buymeacoffee.com/ironsheep) ---- - --------------------- - - - - - - CAUTION -- CAUTION -- CAUTION - - - - - - -------------------- - -Cards are functional but alert coloring not yet working... we are in alpha until we get to funcitonal complete. See releases for card you can test now! Once we release we will submit to HACS as well... - -We are also still working on minor display issues... - --------------------- - - - - - - CAUTION -- CAUTION -- CAUTION - - - - - - -------------------- - ---- ## Installation @@ -54,21 +41,38 @@ In your ui-lovelace.yaml (or resources.yaml, whichever you use for resources) ad If you don't use HACS please change the url accordingly. -## Config +## Configuration | Name | Type | Default | Description | | ------------- | ------ | ------------------ | --------------------------------------------------------------------- | | type | string | **Required** | `custom:rpi-monitor-card` | | entity | string | **Required** | Entity State | -| name | string | none | Overrides default title of the card. | +| name | string | none | Overrides default title of the card. (Default: RPi Monitor {FQDN} | | card_style | string | 'glance' or 'full' | Card layout desired for this RPi. (Default is Full) | | temp_scale | string | 'C' or 'F' | Show Temperature in Celsius (C) or Fahrenheit (F). (Default is C) | -| fs_severity | object | none | A list of severity values. See [Severity Options](#severity-options). | -| temp_severity | object | none | A list of severity values. See [Severity Options](#severity-options). | +| fs_severity | object | none | A list of severity values. See [Severity Coloring](#severity-coloring). | +| temp_severity | object | none | A list of severity values. See [Severity Coloring](#severity-coloring). | + + +### Threashold Monitoring + +Both the 'system temperature' and 'disk space used' values & icons are colored by threshold. The following defaults can be overridden for each card (each RPi.) -We also epxect to have coloring thresholds for free-space and temperature (with reasonable defaults.) +The default coloring is -### Severity Options +| **Value**/color | from | to +| ------------- | ------ | ------------------ +| **Storage Used** % || +| default| 0 | 60 +| yellow| 61| 85 +|red | 86 | 100 +| **Temperature** C || +|default| 0 | 59 +| yellow| 60 | 79 +| red| 80 | 100 + + +### Severity Coloring | Name | Type | Default | Description | | ----- | ------ | ------------ | ------------------------------------------------------- | @@ -78,21 +82,23 @@ We also epxect to have coloring thresholds for free-space and temperature (with ### Example card specifications +**NOTE**: this card must always be attached to the 'sensor.rpi-monitor-{hostname}' sensor, **the other two sensors from the same RPi will not work to drive this card!** + A 'glance' card example ```yaml type: 'custom:rpi-monitor-card' -entity: sensor.rpi-monitor-fqdn +entity: sensor.rpi-monitor-hostname card_style: glance temp_scale: f ``` -A 'full' card example +A 'full' card example (*with additional coloring override example*) ```yaml type: 'custom:rpi-monitor-card' -entity: sensor.rpi-monitor-fqdn +entity: sensor.rpi-monitor-hostname card_style: full temp_scale: C fs_severity: @@ -109,7 +115,8 @@ fs_severity: ## Credits -- [iantrich](https://github.com/iantrich) for the card template and cards you've created which made my implementation effort much easier. +- Ian [iantrich](https://github.com/iantrich) for the card template and cards you've created which made my implementation effort much easier. +- Lucas [Gluwc](https://github.com/Gluwc) for the custom-card: bar-card for his example of how to handle users specifying coloring overrides. ## License @@ -121,6 +128,7 @@ Follow these links for more information: ### [Copyright](copyright) | [License](LICENSE) [maintenance-shield]: https://img.shields.io/badge/maintainer-S%20M%20Moraco%20%40ironsheepbiz-blue.svg?style=for-the-badge +[hacs-shield]: https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge [license-shield]: https://camo.githubusercontent.com/bc04f96d911ea5f6e3b00e44fc0731ea74c8e1e9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f69616e74726963682f746578742d646976696465722d726f772e7376673f7374796c653d666f722d7468652d6261646765 [releases-shield]: https://img.shields.io/github/release/ironsheep/lovelace-rpi-monitor-card.svg?style=for-the-badge [releases]: https://github.com/ironsheep/lovelace-rpi-monitor-card/releases diff --git a/hacs.json b/hacs.json index 9e1bc53..39733d9 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,5 @@ { "name": "RPi Monitor Card", - "render_readme": true, + "render_readme": false, "filename": "rpi-monitor-card.js" } \ No newline at end of file diff --git a/info.md b/info.md new file mode 100644 index 0000000..12637e9 --- /dev/null +++ b/info.md @@ -0,0 +1,120 @@ +# Lovelace RPi Monitor Card + +![Project Maintenance][maintenance-shield] + +[![License][license-shield]](LICENSE) + +[![GitHub Release][releases-shield]][releases] + +![Release](https://github.com/ironsheep/lovelace-rpi-monitor-card/workflows/Release/badge.svg) + +If you have a number of Raspberry Pis on your network then this might be the card you need to setup your Dashboard for monitoring all of you RPi's. Setup the sensor software on your RPi: See [RPi Reporter MQTT2HA Daemon](https://github.com/ironsheep/RPi-Reporter-MQTT2HA-Daemon). Then install this card to display the state of your RPi. + +-- + +This is a Lovelace card showing you the status of one of the Raspberry Pi's on your network. This card offers a choice of smaller 'glance' style card or the larger 'full' card. You choose which you'd like for each of your RPi's. + +![LiveCards](https://user-images.githubusercontent.com/540005/88344532-06257180-cd01-11ea-88ff-fac51d5ca5e6.png) + +Place one of these cards for each of your RPi's on your network (and install the sensor/daemon script on each RPi) and you can monitor your entire constellation of RPi's "at a glance"! + + +## Installation + +Use [HACS](https://github.com/custom-components/hacs) (recommended) +or download _rpi-monitor-card.js_ from our [Latest Release](https://github.com/ironsheep/lovelace-rpi-monitor-card/releases/latest) and place it in your www directory. + +In your ui-lovelace.yaml (or resources.yaml, whichever you use for resources) add this: + +```yaml +- url: /hacsfiles/rpi-monitor-card/rpi-monitor-card.js + type: module +``` + +If you don't use HACS please change the url accordingly. + +## Configuration + +| Name | Type | Default | Description | +| ------------- | ------ | ------------------ | --------------------------------------------------------------------- | +| type | string | **Required** | `custom:rpi-monitor-card` | +| entity | string | **Required** | Entity State | +| name | string | none | Overrides default title of the card. (Default: RPi Monitor {FQDN} | +| card_style | string | 'glance' or 'full' | Card layout desired for this RPi. (Default is Full) | +| temp_scale | string | 'C' or 'F' | Show Temperature in Celsius (C) or Fahrenheit (F). (Default is C) | +| fs_severity | object | none | A list of severity values. See [Severity Coloring](#severity-coloring). | +| temp_severity | object | none | A list of severity values. See [Severity Coloring](#severity-coloring). | + + +### Threashold Monitoring + +Both the 'system temperature' and 'disk space used' values & icons are colored by threshold. The following defaults can be overridden for each card (each RPi.) + +The default coloring is + +| **Value**/color | from | to +| ------------- | ------ | ------------------ +| **Storage Used** % || +| default| 0 | 60 +| yellow| 61| 85 +|red | 86 | 100 +| **Temperature** C || +|default| 0 | 59 +| yellow| 60 | 79 +| red| 80 | 100 + + +### Severity Coloring +Use the following format to override either/or both of 'space used' and 'system temperature' values. + +| Name | Type | Default | Description | +| ----- | ------ | ------------ | ------------------------------------------------------- | +| from | number | **Required** | Defines from which value the color should be displayed. | +| to | number | **Required** | Defines to which value the color should be displayed. | +| color | array | **Required** | Defines the color to be displayed. | + +### Example card specifications + +**NOTE**: this card must always be attached to the 'sensor.rpi-monitor-{hostname}' sensor, **the other two sensors from the same RPi will not work to drive this card!** + +A 'glance' card example + +```yaml +type: 'custom:rpi-monitor-card' +entity: sensor.rpi-monitor-hostname +card_style: glance +temp_scale: f + +``` + +A 'full' card example (*with additional coloring override example*) + +```yaml +type: 'custom:rpi-monitor-card' +entity: sensor.rpi-monitor-hostname +card_style: full +temp_scale: C +fs_severity: + - color: Green + from: 0 + to: 25 + - color: Orange + from: 26 + to: 50 + - color: Red + from: 51 + to: 100 +``` + +--- + +If you like my work and/or this has helped you in some way then feel free to help me out for a couple of :coffee:'s or :pizza: slices! + +[![coffee](https://www.buymeacoffee.com/assets/img/custom_images/black_img.png)](https://www.buymeacoffee.com/ironsheep) + + +[maintenance-shield]: https://img.shields.io/badge/maintainer-S%20M%20Moraco%20%40ironsheepbiz-blue.svg?style=for-the-badge +[hacs-shield]: https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge +[license-shield]: https://camo.githubusercontent.com/bc04f96d911ea5f6e3b00e44fc0731ea74c8e1e9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f69616e74726963682f746578742d646976696465722d726f772e7376673f7374796c653d666f722d7468652d6261646765 +[releases-shield]: https://img.shields.io/github/release/ironsheep/lovelace-rpi-monitor-card.svg?style=for-the-badge +[releases]: https://github.com/ironsheep/lovelace-rpi-monitor-card/releases diff --git a/src/const.ts b/src/const.ts index 98bedab..5d6e20a 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,6 +1,7 @@ -export const CARD_VERSION = '0.9.0'; +export const CARD_VERSION = '1.0.0'; /* +* EXAMPLE attributes { "info": { "timestamp": "2020-07-19T13:17:54-06:00", diff --git a/src/rpi-monitor-card.ts b/src/rpi-monitor-card.ts index 704b8fb..b10e2f2 100644 --- a/src/rpi-monitor-card.ts +++ b/src/rpi-monitor-card.ts @@ -57,6 +57,11 @@ export class RPiMonitorCard extends LitElement { private _updateTimerID: NodeJS.Timeout | undefined; private _hostname: string = ''; private kREPLACE_WITH_TEMP_UNITS: string = 'replace-with-temp-units'; + + // WARNING set following to false before commit! + private _show_debug: boolean = false; + //private _show_debug: boolean = true; + // // FULL-SIZE CARD tables // @@ -164,6 +169,7 @@ export class RPiMonitorCard extends LitElement { Upd: this.kClassIdIconUpdated, }; + // space used icon set private _circleIconsValueByName = { 'circle-outline': 0, 'circle-slice-1': 13, @@ -176,6 +182,74 @@ export class RPiMonitorCard extends LitElement { 'circle-slice-8': 100, }; + /* + * COLORING Goals (default) + * + * 1) color time since reported: yellow if longer than 1 reporting interval, red if two or more + * 2) color space-used: nothing to 60%, 61-85% yellow, 86%+ red + * 3) color temp: nothing to 59C, 60-79C yellow, 80C+ red + */ + + // DEFAULT coloring for used space + // user sets 'fs_severity' to override + private _colorUsedSpaceDefault = [ + { + color: 'undefined', + from: 0, + to: 59, + }, + { + color: 'yellow', + from: 60, + to: 84, + }, + { + color: 'red', + from: 85, + to: 100, + }, + ]; + + // coloring for temp-in-C + // user sets 'temp_severity' to override + private _colorTemperatureDefault = [ + { + color: 'undefined', + from: 0, + to: 59, + }, + { + color: 'yellow', + from: 60, + to: 79, + }, + { + color: 'red', + from: 85, + to: 100, + }, + ]; + + // coloring for temp-in-C + // no user override for now + private _colorReportPeriodsAgoDefault = [ + { + color: 'undefined', + from: 0, + to: 0, + }, + { + color: 'yellow', + from: 1, + to: 1, + }, + { + color: 'red', + from: 2, + to: 100, + }, + ]; + public setConfig(config: RPiMonitorCardConfig): void { // Optional: Check for required fields and that they are of the proper format if (!config || config.show_error) { @@ -186,7 +260,7 @@ export class RPiMonitorCard extends LitElement { const styleValue: string = config.card_style.toLocaleLowerCase(); if (styleValue != 'full' && styleValue != 'glance') { console.log('Invalid configuration. INVALID card_style = [' + config.card_style + ']'); - throw new Error('Illegal card_style: value [card_style:' + config.card_style + ']'); + throw new Error('Illegal card_style: value (card_style: ' + config.card_style + ') must be [full or glance]'); } } @@ -194,7 +268,7 @@ export class RPiMonitorCard extends LitElement { const scaleValue: string = config.temp_scale.toLocaleLowerCase(); if (scaleValue != 'c' && scaleValue != 'f') { console.log('Invalid configuration. INVALID temp_scale = [' + config.temp_scale + ']'); - throw new Error('Illegal temp_scale: value [temp_scale:' + config.temp_scale + ']'); + throw new Error('Illegal temp_scale: value (temp_scale: ' + config.temp_scale + ') must be [F or C]'); } } @@ -218,10 +292,12 @@ export class RPiMonitorCard extends LitElement { this._updateSensorAvailability(); } + /* public getCardSize(): number { // adjust this based on glance or full card type return this._useFullCard() == true ? 3 : 1; } + */ protected shouldUpdate(changedProps: PropertyValues): boolean { //return hasConfigOrEntityChanged(this, changedProps, false); @@ -251,26 +327,32 @@ export class RPiMonitorCard extends LitElement { } const entityId = this._config.entity ? this._config.entity : undefined; - const stateObj = this._config.entity ? this.hass.states[this._config.entity] : undefined; - if (!entityId && !stateObj) { - return this.showWarning('Entity Unavailable'); + if (entityId && !this._sensorAvailable) { + const warningMessage = 'Entity Unavailable: ' + entityId; + return this.showWarning(warningMessage); } - if (!this._sensorAvailable) { + const stateObj = this._config.entity ? this.hass.states[this._config.entity] : undefined; + + if (!entityId && !stateObj) { return this.showWarning('Entity Unavailable'); } if (this._firstTime) { - console.log('- stateObj:'); - console.log(stateObj); + if (this._showDebug()) { + console.log('- stateObj:'); + console.log(stateObj); + } // set timer so our card updates timestamp every 5 seconds : 5000 (1 second: 1000) // FIXME: UNDONE remember to clear this interval when entity NOT avail. and restore when comes avail again... this._startCardRefreshTimer(); - console.log('- 1st-time _config:'); - console.log(this._config); + if (this._showDebug()) { + console.log('- 1st-time _config:'); + console.log(this._config); + } this._firstTime = false; } @@ -484,15 +566,21 @@ export class RPiMonitorCard extends LitElement { const stateObj = this._config.entity ? this.hass.states[this._config.entity] : undefined; if (stateObj != undefined) { const labelElement = root.getElementById('card-timestamp'); - const card_timestamp_value = this._getRelativeTimeSinceUpdate(); - labelElement.textContent = card_timestamp_value; - // now apply color if our entry is OLD - const sinceInMinutes = this._getMinutesSinceUpdate(); - const periodMinutes = this._getAttributeValueForKey(Constants.RPI_SCRIPT_INTERVAL_KEY); - const mumber_periods: number = sinceInMinutes / parseInt(periodMinutes); - const intervalColor = this._computeReporterAgeColor(mumber_periods.toString()); - if (intervalColor != '') { - labelElement.style.setProperty('color', intervalColor); + if (labelElement) { + const card_timestamp_value = this._getRelativeTimeSinceUpdate(); + if (card_timestamp_value) { + labelElement.textContent = card_timestamp_value; + // now apply color if our entry is OLD + /* + const sinceInMinutes = this._getMinutesSinceUpdate(); + const periodMinutes = this._getAttributeValueForKey(Constants.RPI_SCRIPT_INTERVAL_KEY); + const mumber_periods: number = sinceInMinutes / parseInt(periodMinutes); + const intervalColor = this._computeReporterAgeColor(mumber_periods.toString()); + if (intervalColor != '') { + labelElement.style.setProperty('color', intervalColor); + } + */ + } } } } @@ -524,7 +612,9 @@ export class RPiMonitorCard extends LitElement { this._hostname = this._getAttributeValueForKey(Constants.RPI_HOST_NAME_KEY); } const logMessage = '(' + this._hostname + '): ' + message; - console.log(logMessage); + if (this._showDebug()) { + console.log(logMessage); + } } private _updateSensorAvailability(): void { @@ -537,10 +627,15 @@ export class RPiMonitorCard extends LitElement { this._sensorAvailable = false; availChanged = true; // force output in this case } else { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const tmpAvail = this.hass.states[this._config.entity!].state != 'unavailable'; - availChanged = this._sensorAvailable != tmpAvail ? true : false; - this._sensorAvailable = tmpAvail; + try { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const tmpAvail = this.hass.states[this._config.entity!].state != 'unavailable'; + availChanged = this._sensorAvailable != tmpAvail ? true : false; + this._sensorAvailable = tmpAvail; + } catch (error) { + this._sensorAvailable = false; + availChanged = true; // force output in this case + } } } else { this._sensorAvailable = false; @@ -564,71 +659,6 @@ export class RPiMonitorCard extends LitElement { return desiredIconName; } - /* - * COLORING Goals (default) - * - * 1) color time since reported: yellow if longer than 1 reporting interval, red if two or more - * 2) color space-used: nothing to 60%, 61-85% yellow, 86%+ red - * 3) color temp: nothing to 59C, 60-79C yellow, 80C+ red - */ - - // coloring for used space - private _colorUsedSpaceDefault = [ - { - color: 'undefined', - from: 0, - to: 59, - }, - { - color: 'yellow', - from: 60, - to: 84, - }, - { - color: 'red', - from: 85, - to: 100, - }, - ]; - - // coloring for temp-in-C - private _colorTemperatureDefault = [ - { - color: 'undefined', - from: 0, - to: 59, - }, - { - color: 'yellow', - from: 60, - to: 79, - }, - { - color: 'red', - from: 85, - to: 100, - }, - ]; - - // coloring for temp-in-C - private _colorReportPeriodsAgoDefault = [ - { - color: 'undefined', - from: 0, - to: 0, - }, - { - color: 'yellow', - from: 1, - to: 1, - }, - { - color: 'red', - from: 2, - to: 100, - }, - ]; - private _computeReporterAgeColor(value: string): unknown { const numberValue = Number(value); const sections = this._colorReportPeriodsAgoDefault; @@ -736,6 +766,10 @@ export class RPiMonitorCard extends LitElement { return ''; } + if (stateObj?.attributes == undefined) { + return ''; + } + let desired_value: string = ''; // empty string // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (key in stateObj?.attributes!) { @@ -894,6 +928,17 @@ export class RPiMonitorCard extends LitElement { return desiredInterp; } + private _showDebug(): boolean { + // we show debug if enabled in code or if found enabled in config for this card! + let showDebugStatus = this._show_debug; + if (this._config) { + if (this._config.show_debug != undefined) { + showDebugStatus = showDebugStatus == true || this._config.show_debug == true; + } + } + return showDebugStatus; + } + static get styles(): CSSResult { // style our GLANCE card return css` diff --git a/src/types.ts b/src/types.ts index 5edd161..004ebed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -23,6 +23,7 @@ export interface RPiMonitorCardConfig extends LovelaceCardConfig { show_warning?: boolean; show_error?: boolean; test_gui?: boolean; + show_debug?: boolean; tap_action?: ActionConfig; hold_action?: ActionConfig;