diff --git a/README.md b/README.md index c0be669..67015e3 100644 --- a/README.md +++ b/README.md @@ -40,16 +40,44 @@ The easiest way to find that entity name is by opening the Search within Home As (The format is, for example: `event.octopus_energy_electricity_{METER_SERIAL_NUMBER}}_{{MPAN_NUMBER}}_current_day_rates`) -Here's an example yaml configuration - obviously replacing `` with your data from above. +Here's an example yaml configuration - obviously replacing `` with your data from above. ``` -currentEntity: event.octopus_energy_electricity__current_day_rates -pastEntity: event.octopus_energy_electricity__previous_day_rates -futureEntity: event.octopus_energy_electricity__next_day_rates type: custom:octopus-energy-rates-card +currentEntity: event.octopus_energy_electricity__current_day_rates cols: 2 +hour12: false showday: true showpast: false +title: Octopus Import +unitstr: p +lowlimit: 15 +mediumlimit: 20 +highlimit: 30 +roundUnits: 2 +cheapest: true +multiplier: 100 + +``` +and here is one for export rates: +``` +type: custom:octopus-energy-rates-card +pastEntity: event.octopus_energy_electricity__export_previous_day_rates +currentEntity: event.octopus_energy_electricity__export_current_day_rates +futureEntity: event.octopus_energy_electricity_22l4132637__export_next_day_rates +cols: 3 +hour12: false +showday: false +showpast: false +title: Octopus Export +unitstr: p +lowlimit: null +mediumlimit: 10 +highlimit: 19 +roundUnits: 2 +cheapest: true +multiplier: 100 +exportrates: true ``` Here's a breakdown of all the available configuration items: @@ -59,10 +87,12 @@ Here's a breakdown of all the available configuration items: | currentEntity | N | N/A | Name of the sensor that contains the current rates you want to render, generated from the `HomeAssistant-OctopusEnergy` integration | | pastEntity | Y | N/A | Name of the sensor that contains the past rates you want to render, generated from the `HomeAssistant-OctopusEnergy` integration | | futureEntity | Y | N/A | Name of the sensor that contains the future rates you want to render, generated from the `HomeAssistant-OctopusEnergy` integration | +| targetTimesEntity | Y | N/A | Name of the sensor that contains the Target Rate Sensor, generated from the `HomeAssistant-OctopusEnergy` integration. [More here: doc](https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/blob/develop/_docs/setup_target_rate.md) | | cols | Y | 1 | How many columns to break the rates in to, pick the one that fits best with how wide your card is | | showpast | Y | false | Show the rates that have already happened today. Provides a simpler card when there are two days of dates to show | | showday | Y | false | Shows the (short) day of the week next to the time for each rate. Helpful if it's not clear which day is which if you have a lot of rates to display | | title | Y | "Agile Rates" | The title of the card in the dashboard | +| lowlimit | Y | 5 (pence) | If the price is above `lowlimit`, the row is marked dark green. (this option is only applicable for import rates | | mediumlimit | Y | 20 (pence) | If the price is above `mediumlimit`, the row is marked yellow | | highlimit | Y | 30 (pence) | If the price is above `highlimit`, the row is marked red. | | roundUnits | Y | 2 | Controls how many decimal places to round the rates to | @@ -78,14 +108,42 @@ Here's a breakdown of all the available configuration items: #### A note on colouring -* The card is hardcoded to display plunge pricing (e.g, below 0p/kWh) as blue -* If the price is above `highlimit`, then the row is in red -* If the price is above `mediumlimit`, then the row is coloured orange/yellow -* Otherwise, the row is coloured is green. -* These are reversed if `exportrates` is set to `true` +* The card is hardcoded to display plunge pricing (e.g, below 0p/kWh) as blue. +* If the price is above `highLimit`, then the row is in red +* If the price is above `mediumLimit`, then the row is coloured orange +* if the price is above `lowLimit`, then the row is coloured dark green +* if the price is below `lowLimit`, then the row is coloured green +* These are reversed if `exportrates` is set to `true` (export rates have only 3 colours, red, orange and green) +* Cheapest rate is coloured in light green (above 0) / light blue (below 0) +* If Target Rate entity is included in the config, the target hours will be highlited in Navy Blue + +#### Screenshots +![screenshot_1](assets/import.png) +![screenshot_2](assets/export.png) + +##### Advanced Configurations + +Import rates with the Target Rates and future rates entities specified: +``` +type: custom:octopus-energy-rates-card +currentEntity: event.octopus_energy_electricity_22l4132637_1900026354329_current_day_rates +futureEntity: event.octopus_energy_electricity_22l4132637_1900026354329_next_day_rates +targetTimesEntity: binary_sensor.octopus_energy_target_intermittent_best_charging_rates +cols: 3 +hour12: false +showday: false +showpast: false +title: Octopus Import - p/kWh +unitstr: '' +lowlimit: 6 +mediumlimit: 15 +highlimit: 27 +cheapest: true +multiplier: 100 +``` +![screenshot_3](assets/import_with_target.png) + -#### Screenshot -![screenshot_1](assets/screenshot_1.png) #### Thanks/inspiration This card was based on and reworked from the code [markgdev/home-assistant_OctopusAgile](https://github.com/markgdev/home-assistant_OctopusAgile/tree/master/custom_cards) which is no longer maintained. diff --git a/assets/export.png b/assets/export.png new file mode 100644 index 0000000..0a737a6 Binary files /dev/null and b/assets/export.png differ diff --git a/assets/import.png b/assets/import.png new file mode 100644 index 0000000..f29fb93 Binary files /dev/null and b/assets/import.png differ diff --git a/assets/import_with_target.png b/assets/import_with_target.png new file mode 100644 index 0000000..ca62bc7 Binary files /dev/null and b/assets/import_with_target.png differ diff --git a/octopus-energy-rates-card.js b/octopus-energy-rates-card.js index 598517d..ac3d0c4 100644 --- a/octopus-energy-rates-card.js +++ b/octopus-energy-rates-card.js @@ -21,6 +21,10 @@ class OctopusEnergyRatesCard extends HTMLElement { table.main { padding: 0px; } + td.time_highlight { + font-weight: bold; + background-color: Navy; + } thead th { text-align: left; padding: 0px; @@ -47,6 +51,9 @@ class OctopusEnergyRatesCard extends HTMLElement { td.time_green{ border-bottom: 1px solid MediumSeaGreen; } + td.time_lightgreen { + border-bottom: 1px solid ForestGreen; + } td.time_blue{ border-bottom: 1px solid #391CD9; } @@ -77,6 +84,10 @@ class OctopusEnergyRatesCard extends HTMLElement { border: 2px solid MediumSeaGreen; background-color: MediumSeaGreen; } + td.lightgreen { + border: 2px solid ForestGreen; + background-color: ForestGreen; + } td.blue { border: 2px solid #391CD9; background-color: #391CD9; @@ -97,12 +108,17 @@ class OctopusEnergyRatesCard extends HTMLElement { this.appendChild(card); } - const colours_import = ['green', 'red', 'orange', 'blue', 'cheapest', 'cheapestblue']; - const colours_export = [ 'red', 'green', 'orange' ]; - + const colours_import = ['lightgreen', 'green', 'orange', 'red', 'blue', 'cheapest', 'cheapestblue']; + const colours_export = [ 'red', 'green', 'orange', 'green' ]; const currentEntityId = config.currentEntity; const futureEntityId = config.futureEntity; const pastEntityId = config.pastEntity; + // Read the targetTimes entity if specified + const targetTimesId = config.targetTimesEntity; + const targetTimesstate = hass.states[targetTimesId]; + const targetTimesttributes = targetTimesstate ? this.reverseObject(targetTimesstate.attributes) : {}; + + const lowlimit = config.lowlimit; const mediumlimit = config.mediumlimit; const highlimit = config.highlimit; const unitstr = config.unitstr; @@ -116,6 +132,8 @@ class OctopusEnergyRatesCard extends HTMLElement { var colours = (config.exportrates ? colours_export : colours_import); var rates_totalnumber = 0; var combinedRates = []; + // Check if slotsTargetTimes is available before using forEach + const slotsTargetTimes = targetTimesttributes.target_times || []; // Grab the rates which are stored as an attribute of the sensor const paststate = hass.states[pastEntityId]; @@ -230,16 +248,30 @@ class OctopusEnergyRatesCard extends HTMLElement { // If the showday config option is set, include the shortened weekday name in the user's Locale var date_locale = (showday ? date.toLocaleDateString(lang, { weekday: 'short' }) + ' ' : ''); - var colour = colours[0]; + var colour = colours[1]; // Default to 'green' (index 1) (below low limit above 0) + var isTargetTime = false; + // Check if the current time row corresponds to a target time + slotsTargetTimes.forEach(function (targetTime) { + const startTime = new Date(targetTime.start); + const endTime = new Date(targetTime.end); + if (date >= startTime && date < endTime) { + isTargetTime = true; + } + }); + + var valueToDisplay = key.value_inc_vat * multiplier; - if (cheapest && (valueToDisplay == cheapest_rate && cheapest_rate > 0)) colour = colours[4]; - else if (cheapest && (valueToDisplay == cheapest_rate && cheapest_rate <= 0)) colour = colours[5]; - else if (valueToDisplay > highlimit) colour = colours[1]; - else if (valueToDisplay > mediumlimit) colour = colours[2]; - else if (valueToDisplay <= 0) colour = colours[3]; + // Apply bold styling if the current time is a target time + var boldStyle = isTargetTime ? 'time_highlight' : ''; + if (cheapest && (valueToDisplay == cheapest_rate && cheapest_rate > 0)) colour = colours[5]; + else if (cheapest && (valueToDisplay == cheapest_rate && cheapest_rate <= 0)) colour = colours[6]; + else if (valueToDisplay > highlimit) colour = colours[3]; //red (import) / green (export) + else if (valueToDisplay > mediumlimit) colour = colours[2]; // orange (import) / orange (export) + else if (valueToDisplay > lowlimit) colour = colours[0]; // lightgreen (import) / red (export) + else if (valueToDisplay <= 0) colour = colours[4]; // below 0 - blue (import/export) if(showpast || (date - Date.parse(new Date())>-1800000)) { - table = table.concat("" + date_locale + time_locale + + table = table.concat("" + date_locale + time_locale + "" + valueToDisplay.toFixed(roundUnits) + unitstr + ""); if (x % rows_per_col == 0) { @@ -287,6 +319,8 @@ class OctopusEnergyRatesCard extends HTMLElement { } const defaultConfig = { + // Entities to get data from + targetTimesEntity: null, // Controls how many columns the rates split in to cols: 1, // Show rates that already happened in the card @@ -299,11 +333,13 @@ class OctopusEnergyRatesCard extends HTMLElement { title: 'Agile Rates', // Colour controls: // If the price is above highlimit, the row is marked red. - // If the price is above mediumlimit, the row is marked yellow. - // If the price is below mediumlimit, the row is marked green. + // If the price is above mediumlimit, the row is marked orange. + // If the price is above lowlimit, the row is marked dark green. + // If the price is below lowlimit, the row is marked green. // If the price is below 0, the row is marked blue. - mediumlimit: 20, - highlimit: 30, + lowlimit: 0.05, + mediumlimit: 0.10, + highlimit: 0.30, // Controls the rounding of the units of the rate roundUnits: 2, // The unit string to show if units are shown after each rate