11import logging
2- from datetime import date , timedelta
3- from homeassistant .components .sensor import SensorEntity
2+ from datetime import date , datetime , timedelta
3+ from math import ceil
4+ from homeassistant .components .sensor import SensorEntity , SensorDeviceClass
5+ from homeassistant .helpers .entity import EntityCategory
46from homeassistant .helpers .update_coordinator import CoordinatorEntity , DataUpdateCoordinator
57from .const import *
68
79_LOGGER = logging .getLogger (__name__ )
810
911ICON = "mdi:calendar-clock"
12+ ICON_DAYS_TO = "mdi:calendar-end"
1013
1114async def async_setup_entry (hass , entry , async_add_entities ):
1215 data = hass .data [DOMAIN ][entry .entry_id ]
1316 coordinator : DataUpdateCoordinator = data ["coordinator" ]
1417 instance_name = data .get ("name" , "IsItPayday" )
1518
16- async_add_entities ([IsItPaydayNextSensor (coordinator , entry .entry_id , instance_name )])
19+ async_add_entities ([
20+ IsItPaydayNextSensor (coordinator , entry .entry_id , instance_name ),
21+ IsItPaydayDaysToSensor (coordinator , entry .entry_id , instance_name )
22+ ])
1723
1824
1925class IsItPaydayNextSensor (CoordinatorEntity , SensorEntity ):
@@ -35,20 +41,15 @@ def state(self) -> str:
3541
3642 today = date .today ()
3743
38- # Parse to date if it's a string
3944 if not isinstance (payday , date ):
4045 try :
4146 payday = date .fromisoformat (payday )
4247 except (ValueError , TypeError ):
4348 return "Unknown"
4449
45- # If payday is today, we want to keep it until the day ends
46- if payday > today :
50+ if payday >= today :
4751 return payday .strftime ("%Y-%m-%d" )
48- elif payday == today :
49- return payday .strftime ("%Y-%m-%d" )
50- else :
51- return "Unknown"
52+ return "Unknown"
5253
5354 @property
5455 def extra_state_attributes (self ) -> dict :
@@ -65,3 +66,54 @@ def device_info(self):
6566 "manufacturer" : CONF_MANUFACTURER ,
6667 "model" : CONF_MODEL ,
6768 }
69+
70+
71+ class IsItPaydayDaysToSensor (CoordinatorEntity , SensorEntity ):
72+ _attr_device_class = SensorDeviceClass .DURATION
73+ _attr_native_unit_of_measurement = "d"
74+ _attr_state_class = "measurement"
75+ _attr_entity_category = EntityCategory .DIAGNOSTIC
76+
77+ def __init__ (self , coordinator : DataUpdateCoordinator , entry_id : str , instance_name : str ):
78+ super ().__init__ (coordinator )
79+ self ._attr_unique_id = f"{ entry_id } _days_to"
80+ self ._attr_name = f"{ instance_name } : Days to"
81+ self ._attr_icon = ICON_DAYS_TO
82+ self ._instance_name = instance_name
83+ self ._entry_id = entry_id
84+
85+ @property
86+ def native_value (self ) -> int | None :
87+ payday = self .coordinator .data .get ("payday_next" )
88+ if not payday :
89+ return None
90+
91+ try :
92+ if isinstance (payday , str ):
93+ payday = date .fromisoformat (payday )
94+
95+ now = datetime .now ().date ()
96+ if payday <= now :
97+ return 0
98+
99+ delta = payday - now
100+ return delta .days
101+ except Exception as e :
102+ _LOGGER .exception ("Error calculating days to payday: %s" , e )
103+ return None
104+
105+ @property
106+ def extra_state_attributes (self ) -> dict :
107+ return {
108+ "source" : "IsItPayday DataUpdateCoordinator" ,
109+ "raw_data" : str (self .coordinator .data ),
110+ }
111+
112+ @property
113+ def device_info (self ):
114+ return {
115+ "identifiers" : {(DOMAIN , self ._entry_id )},
116+ "name" : self ._instance_name ,
117+ "manufacturer" : CONF_MANUFACTURER ,
118+ "model" : CONF_MODEL ,
119+ }
0 commit comments