diff --git a/README.md b/README.md index 56483e9..e9466b4 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,6 @@ If you think this will be useful to you, please consider signing up to Octopus E Octoblock is an app which works under [AppDaemon](https://www.home-assistant.io/docs/ecosystem/appdaemon/) within [Home Assistant](https://www.home-assistant.io/) which finds the cheapest ā€œnā€ hour block for import or the most expensive ā€œnā€ hour block for export, and works out the price of that block, for the Octopus Energy, Agile Octopus / Agile Outgoing Octopus tariffs. -*Please note:* *Breaking Changes!* New yaml structure in version 2! - It creates and sets sensors for the cost and start time, for example, using the `apps.yaml` file below, the following entities are created and then updated: ```yaml sensor.octopus_1hour_time @@ -26,13 +24,20 @@ sensor.octopus_export_1hour_time sensor.octopus_export_1hour_price ``` +Sensor names can be overridden and your own name specified in the yaml configuration. These will be of the format `sensor._time` and `sensor._price` with any dots in `` changed to underscores. + +### Special Cases With `start_period` set to `now` and `hour` set to `0` the current import or export price is returned, and the sensors are named: ```yaml sensor.octopus_current_price sensor.octopus_export_current_price ``` -Sensor names can be overridden and your own name specified in the yaml configuration. These will be of the format `sensor._time` and `sensor._price` with any dots in `` changed to underscores. +With `start_period` set to `now` and `hour` set to `next` the next import or export price is returned, and the sensors are named: +```yaml +sensor.octopus_next_price +sensor.octopus_export_next_price +``` ## Installation diff --git a/apps/octoblock/octoblock.py b/apps/octoblock/octoblock.py index e83b3d3..41fec4e 100644 --- a/apps/octoblock/octoblock.py +++ b/apps/octoblock/octoblock.py @@ -92,7 +92,7 @@ def get_import_prices(self): ) tariff = json.loads(r.text) - self.incoming_tariff = tariff[u"results"] + self.incoming_tariff = tariff["results"] self.incoming_tariff.reverse() def get_export_prices(self): @@ -113,7 +113,7 @@ def get_export_prices(self): ) tariff = json.loads(r.text) - self.outgoing_tariff = tariff[u"results"] + self.outgoing_tariff = tariff["results"] self.outgoing_tariff.reverse() def calculate_limit_points(self): @@ -232,50 +232,38 @@ def date_to_idx(cls, tariff, date): return idx def get_current_period_and_cost(self, tariffresults): + now_or_next = "Current" if self.hours == 0 else "Next" + direction = "import" if self.incoming else "export" now_utc_flr = self.floor_dt(datetime.datetime.utcnow()) api_date_now = self.dt_to_api_date(now_utc_flr) self.log( - "**Now API Date get_period_and_cost: {} **".format(api_date_now), - level="DEBUG", + f"**Now API Date get_period_and_cost: {api_date_now} **", level="DEBUG" ) i = self.date_to_idx(tariffresults, api_date_now) - if self.incoming: - self.price = tariffresults[i]["value_inc_vat"] - self.log( - "Current import price is: {} p/kWh".format(self.price), level="INFO" - ) - self.log( - "**Tariff Date get_period_and_cost: {} **".format( - tariffresults[i]["valid_from"] - ), - level="DEBUG", - ) - - elif self.outgoing: - self.price = tariffresults[i]["value_inc_vat"] - self.log( - "Current export price is: {} p/kWh".format(self.price), level="INFO" - ) - self.log( - "**Tariff Date get_period_and_cost: {} **".format( - tariffresults[i]["valid_from"] - ), - level="DEBUG", - ) + if str(self.hours).lower() == "next": + i += 1 + self.price = tariffresults[i]["value_inc_vat"] + self.log( + f"{now_or_next} {direction} price is: {self.price} p/kWh", level="INFO" + ) + self.log( + f"**Tariff Date get_period_and_cost: {tariffresults[i]['valid_from']} **", + level="DEBUG", + ) def get_period_and_cost(self): - blocks = float(self.hours) * 2 - blocks = int(blocks) if self.incoming: tariffresults = self.incoming_tariff else: tariffresults = self.outgoing_tariff - if self.hours == 0: + if self.hours == 0 or str(self.hours).lower() == "next": self.get_current_period_and_cost(tariffresults) else: + blocks = float(self.hours) * 2 + blocks = int(blocks) start_idx = self.date_to_idx(tariffresults, self.start_date) end_idx = self.date_to_idx(tariffresults, self.end_date) if not end_idx: @@ -297,7 +285,7 @@ def get_period_and_cost(self): continue cost = 0 for block in range(blocks): - cost = cost + (tariffresults[curridx + block][u"value_inc_vat"]) + cost = cost + (tariffresults[curridx + block]["value_inc_vat"]) cost = cost / blocks period[str(self.hours) + "_hour_average"] = cost @@ -327,7 +315,7 @@ def get_period_and_cost(self): for curridx in range(start_idx, end_idx): period = tariffresults[curridx] if period[str(self.hours) + "_hour_average"] == self.price: - self.time = period[u"valid_from"] + self.time = period["valid_from"] self.log("**Time: {}**".format(self.time), level="DEBUG") if self.use_timezone: @@ -357,6 +345,12 @@ def write_block_sensor_data(self): state=round(self.price, 4), attributes={"unit_of_measurement": "p/kWh", "icon": "mdi:flash"}, ) + elif str(self.hours).lower() == "next": + self.set_state( + "sensor.octopus_next_price", + state=round(self.price, 4), + attributes={"unit_of_measurement": "p/kWh", "icon": "mdi:flash"}, + ) else: if not self.name: entity_id_t = "sensor.octopus_" + hours + "hour_time" @@ -382,6 +376,15 @@ def write_block_sensor_data(self): "icon": "mdi:flash-outline", }, ) + elif str(self.hours).lower() == "next": + self.set_state( + "sensor.octopus_export_next_price", + state=round(self.price, 4), + attributes={ + "unit_of_measurement": "p/kWh", + "icon": "mdi:flash-outline", + }, + ) else: if not self.name: entity_id_t = "sensor.octopus_export" + hours + "hour_time"