2024-12-07 15:22:08 +01:00
import json
import logging
import paho . mqtt . client as mqtt
from . screen import Screen
from . select import Selector
logger = logging . getLogger ( __name__ )
class HAClient :
2024-12-08 10:43:31 +01:00
def __init__ (
self ,
entity : str ,
secondary_entities : list [ str ] = [ ] ,
config : dict = dict ( ) ,
) - > None :
2024-12-07 15:22:08 +01:00
self . entity = entity
self . secondary_entities = secondary_entities
2024-12-08 10:43:31 +01:00
self . config = config
2024-12-07 15:22:08 +01:00
self . state_topic = " oin/state "
self . availability_topic = " oin/availability "
self . client = mqtt . Client ( mqtt . CallbackAPIVersion . VERSION2 )
2024-12-08 10:43:31 +01:00
self . client . username_pw_set (
username = self . config . get ( " username " , None ) ,
password = self . config . get ( " password " , None ) ,
)
2024-12-07 15:22:08 +01:00
self . screen = Screen ( )
self . selector = Selector ( self . send_data )
@property
2024-12-08 10:43:31 +01:00
def ha_options ( self ) - > dict [ str , str | dict [ str , str ] ] :
2024-12-07 15:22:08 +01:00
return {
" dev " : {
" ids " : " oin " ,
" name " : " Oin " ,
} ,
" o " : {
" name " : " Oin " ,
} ,
" availability_topic " : self . availability_topic ,
" state_topic " : self . state_topic ,
" cmps " : self . selector . ha_options ,
}
2024-12-08 10:43:31 +01:00
def connect ( self ) - > None :
2024-12-07 15:22:08 +01:00
logger . debug ( " Connecting to HA... " )
self . client . will_set ( self . availability_topic , " offline " , retain = True )
2024-12-08 10:43:31 +01:00
self . client . connect ( self . config . get ( " host " ) , self . config . get ( " port " , 1883 ) )
2024-12-07 15:22:08 +01:00
self . subscribe ( entity_topic ( self . entity ) , self . state_update )
for entity in self . secondary_entities :
self . subscribe ( entity_topic ( entity , " state " ) , self . secondary_state_update )
self . publish ( " homeassistant/device/oin/config " , self . ha_options , retain = True )
self . client . publish ( self . availability_topic , " online " , retain = True )
def publish ( self , topic , data , * * kwargs ) :
logger . debug ( f " Sending message on topic < { topic } >: { json . dumps ( data ) } " )
self . client . publish ( topic , json . dumps ( data ) , * * kwargs )
def subscribe ( self , topic , callback ) :
logger . debug ( f " Subscribe to < { topic } > " )
self . client . subscribe ( topic )
self . client . message_callback_add ( topic , callback )
def unsubscribe ( self , topic ) :
logger . debug ( f " Unsubscribe from < { topic } > " )
self . client . unsubscribe ( topic )
def loop ( self ) :
logger . info ( " Starting MQTT client loop " )
self . client . loop_forever ( )
def state_update ( self , client : mqtt . Client , userdata , message : mqtt . MQTTMessage ) :
logger . debug ( f " Message received on topic < { message . topic } >: { message . payload } . " )
subtopic = message . topic . rsplit ( " / " , maxsplit = 1 ) [ 1 ]
match subtopic :
case " current_temperature " :
self . screen . value = parse ( message )
case " temperature " :
if ( value := parse ( message ) ) != self . selector . temperature :
self . screen . tmp_value = value
self . selector . temperature = value
case " hvac_action " :
self . screen . mode = parse ( message )
case " preset_modes " :
if ( value := parse ( message ) ) != self . selector . preset_modes :
self . selector . preset_modes = value
case " preset_mode " :
if ( value := parse ( message ) ) != self . selector . mode :
self . selector . mode = value
case " state " :
match message . payload . decode ( ) :
case " heat " :
self . selector . switch = True
case " off " :
self . selector . switch = False
def secondary_state_update (
self , client : mqtt . Client , userdata , message : mqtt . MQTTMessage
) :
logger . debug ( f " Message received on topic < { message . topic } >: { message . payload } . " )
_ , grp , ent , subtopic = message . topic . split ( " / " )
idx = self . secondary_entities . index ( f " { grp } . { ent } " )
if subtopic == " state " :
self . screen . secondary | = { idx : message . payload . decode ( ) }
def send_data ( self , data ) :
self . publish ( self . state_topic , data )
def parse ( message ) :
return json . loads ( message . payload . decode ( ) )
def entity_topic ( entity , subtopic = " # " ) :
topic = entity . replace ( " . " , " / " )
return f " homeassistant/ { topic } / { subtopic } "