Update mqtt_publisher.py
This commit is contained in:
@ -104,75 +104,119 @@ class PstrykMqttPublisher:
|
|||||||
# First, check if we're in 48h mode
|
# First, check if we're in 48h mode
|
||||||
mqtt_48h_mode = self.hass.data[DOMAIN].get(f"{self.entry_id}_mqtt_48h_mode", False)
|
mqtt_48h_mode = self.hass.data[DOMAIN].get(f"{self.entry_id}_mqtt_48h_mode", False)
|
||||||
|
|
||||||
# Get current date for comparison
|
# Get current date for comparison - in local time
|
||||||
now = dt_util.as_local(dt_util.utcnow())
|
now_local = dt_util.as_local(dt_util.utcnow())
|
||||||
today_str = now.strftime("%Y-%m-%d")
|
today_date = now_local.date()
|
||||||
tomorrow_str = (now + timedelta(days=1)).strftime("%Y-%m-%d")
|
tomorrow_date = (now_local + timedelta(days=1)).date()
|
||||||
|
|
||||||
# Get the appropriate price list based on mode
|
# Get all prices from coordinator
|
||||||
if mqtt_48h_mode:
|
all_prices = prices_data.get("prices", [])
|
||||||
price_list = prices_data.get("prices", [])
|
|
||||||
|
|
||||||
# In 48h mode, we need to check if tomorrow's data is valid
|
# Process prices and group by date
|
||||||
# Separate today and tomorrow prices
|
prices_by_date = {}
|
||||||
today_prices = [p for p in price_list if p.get("start", "").startswith(today_str)]
|
for price_entry in all_prices:
|
||||||
tomorrow_prices = [p for p in price_list if p.get("start", "").startswith(tomorrow_str)]
|
|
||||||
|
|
||||||
# Always include today's prices
|
|
||||||
prices_to_process = today_prices.copy()
|
|
||||||
|
|
||||||
# Only include tomorrow if the data looks valid
|
|
||||||
if tomorrow_prices and self._is_day_data_valid(tomorrow_prices):
|
|
||||||
prices_to_process.extend(tomorrow_prices)
|
|
||||||
_LOGGER.info(f"Including {len(tomorrow_prices)} tomorrow prices in MQTT publish")
|
|
||||||
else:
|
|
||||||
if tomorrow_prices:
|
|
||||||
_LOGGER.info(f"Excluding {len(tomorrow_prices)} tomorrow prices from MQTT - appear to be placeholders")
|
|
||||||
else:
|
|
||||||
_LOGGER.debug("No tomorrow prices available for MQTT publish")
|
|
||||||
else:
|
|
||||||
# In normal mode, use only today's prices
|
|
||||||
prices_to_process = prices_data.get("prices_today", [])
|
|
||||||
|
|
||||||
# Process the selected prices
|
|
||||||
for price_entry in prices_to_process:
|
|
||||||
try:
|
try:
|
||||||
if "start" not in price_entry or "price" not in price_entry:
|
if "start" not in price_entry or "price" not in price_entry:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Validate price is a number
|
# Parse the datetime (it's already in local time from coordinator)
|
||||||
try:
|
price_datetime = dt_util.parse_datetime(price_entry["start"])
|
||||||
price_value = float(price_entry["price"])
|
if not price_datetime:
|
||||||
except (TypeError, ValueError):
|
|
||||||
_LOGGER.warning("Invalid price value: %s", price_entry.get("price"))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Parse local time and convert to UTC ISO format
|
# Ensure it's local time
|
||||||
local_dt = dt_util.parse_datetime(price_entry["start"])
|
price_datetime_local = dt_util.as_local(price_datetime)
|
||||||
if not local_dt:
|
price_date = price_datetime_local.date()
|
||||||
continue
|
|
||||||
|
|
||||||
utc_dt = dt_util.as_utc(local_dt)
|
if price_date not in prices_by_date:
|
||||||
|
prices_by_date[price_date] = []
|
||||||
|
|
||||||
# Calculate end time (1 hour later)
|
prices_by_date[price_date].append(price_entry)
|
||||||
end_dt = utc_dt + timedelta(hours=1)
|
|
||||||
|
|
||||||
# Format times in ISO format with Z suffix for UTC
|
|
||||||
start_str = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
end_str = end_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
|
|
||||||
# EVCC w trybie custom pokazuje ceny jako "gr" (grosze),
|
|
||||||
price_value = price_value / 1
|
|
||||||
|
|
||||||
formatted_prices.append({
|
|
||||||
"start": start_str,
|
|
||||||
"end": end_str,
|
|
||||||
"value": price_value
|
|
||||||
})
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_LOGGER.error("Error formatting price for EVCC: %s", str(e))
|
_LOGGER.error("Error processing price entry: %s", str(e))
|
||||||
|
|
||||||
|
# Determine which days to include
|
||||||
|
days_to_include = []
|
||||||
|
|
||||||
|
if mqtt_48h_mode:
|
||||||
|
# In 48h mode, include today and tomorrow
|
||||||
|
if today_date in prices_by_date:
|
||||||
|
days_to_include.append(today_date)
|
||||||
|
|
||||||
|
if tomorrow_date in prices_by_date:
|
||||||
|
# Check if tomorrow's data is valid
|
||||||
|
tomorrow_prices = prices_by_date[tomorrow_date]
|
||||||
|
if self._is_day_data_valid(tomorrow_prices):
|
||||||
|
days_to_include.append(tomorrow_date)
|
||||||
|
_LOGGER.info(f"Including {len(tomorrow_prices)} tomorrow prices in MQTT publish")
|
||||||
|
else:
|
||||||
|
_LOGGER.info(f"Excluding tomorrow prices from MQTT - appear to be placeholders or incomplete")
|
||||||
|
else:
|
||||||
|
# In 24h mode, only include today
|
||||||
|
if today_date in prices_by_date:
|
||||||
|
days_to_include.append(today_date)
|
||||||
|
|
||||||
|
# Process selected days
|
||||||
|
for date_to_include in sorted(days_to_include):
|
||||||
|
day_prices = prices_by_date.get(date_to_include, [])
|
||||||
|
|
||||||
|
# Sort by time to ensure correct order
|
||||||
|
day_prices.sort(key=lambda x: x["start"])
|
||||||
|
|
||||||
|
for price_entry in day_prices:
|
||||||
|
try:
|
||||||
|
# Validate price is a number
|
||||||
|
try:
|
||||||
|
price_value = float(price_entry["price"])
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
_LOGGER.warning("Invalid price value: %s", price_entry.get("price"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse local time and convert to UTC ISO format
|
||||||
|
local_dt = dt_util.parse_datetime(price_entry["start"])
|
||||||
|
if not local_dt:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ensure it's local time and convert to UTC
|
||||||
|
local_dt = dt_util.as_local(local_dt)
|
||||||
|
utc_dt = dt_util.as_utc(local_dt)
|
||||||
|
|
||||||
|
# Calculate end time (1 hour later)
|
||||||
|
end_dt = utc_dt + timedelta(hours=1)
|
||||||
|
|
||||||
|
# Format times in ISO format with Z suffix for UTC
|
||||||
|
start_str = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
end_str = end_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
formatted_prices.append({
|
||||||
|
"start": start_str,
|
||||||
|
"end": end_str,
|
||||||
|
"value": price_value
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
_LOGGER.error("Error formatting price for EVCC: %s", str(e))
|
||||||
|
|
||||||
|
# Log summary
|
||||||
|
if formatted_prices:
|
||||||
|
first_time = formatted_prices[0]["start"]
|
||||||
|
last_time = formatted_prices[-1]["start"]
|
||||||
|
_LOGGER.debug(f"Formatted {len(formatted_prices)} prices for MQTT from {first_time} to {last_time}")
|
||||||
|
|
||||||
|
# Verify we have complete days
|
||||||
|
hours_by_date = {}
|
||||||
|
for fp in formatted_prices:
|
||||||
|
date_part = fp["start"][:10] # YYYY-MM-DD
|
||||||
|
if date_part not in hours_by_date:
|
||||||
|
hours_by_date[date_part] = 0
|
||||||
|
hours_by_date[date_part] += 1
|
||||||
|
|
||||||
|
for date, hours in hours_by_date.items():
|
||||||
|
if hours != 24:
|
||||||
|
_LOGGER.warning(f"Incomplete day {date}: only {hours} hours instead of 24")
|
||||||
|
else:
|
||||||
|
_LOGGER.warning("No prices formatted for MQTT")
|
||||||
|
|
||||||
_LOGGER.debug(f"Formatted {len(formatted_prices)} prices for MQTT from {len(prices_to_process)} input prices")
|
|
||||||
return formatted_prices
|
return formatted_prices
|
||||||
|
|
||||||
async def publish_prices(self):
|
async def publish_prices(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user