@ -40,6 +40,7 @@ class InfluxOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ,  url ,  token ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Initialize  InfluxOutputPlugin  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        https : / / influxdb - client . readthedocs . io / en / stable / api . html #influxdbclient  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        The  following  targets  must  be  present  in  your  InfluxDB .  This  does  not  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        automatically  create  anything  for  You .  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -69,8 +70,12 @@ class InfluxOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . _org  =  params . get ( ' org ' ,  ' ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . _measurement  =  params . get ( ' measurement ' ,  f ' inverter,host= { socket . gethostname ( ) } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        client  =  InfluxDBClient ( url ,  token ,  bucket = self . _bucket )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . api  =  client . write_api ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        with  InfluxDBClient ( url ,  token ,  bucket = self . _bucket )  as  self . client :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					             self . api  =  self . client . write_api ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  disco ( self ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . client . close ( )           # Shutdown the client  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  store_status ( self ,  response ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -103,6 +108,9 @@ class InfluxOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # InfluxDB requires nanoseconds  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        ctime  =  int ( utctime . timestamp ( )  *  1e9 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            logging . info ( f ' InfluxDB: utctime:  { utctime } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # AC Data  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        phase_id  =  0  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        for  phase  in  data [ ' phases ' ] :  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -136,6 +144,9 @@ class InfluxOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            data_stack . append ( f ' { measurement } ,type=YieldToday value= { data [ " yield_today " ] / 1000 : .3f }   { ctime } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        data_stack . append ( f ' { measurement } ,type=Efficiency value= { data [ " efficiency " ] : .2f }   { ctime } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            #logging.debug(f'INFLUX data to DB: {data_stack}')  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            pass  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . api . write ( self . _bucket ,  self . _org ,  data_stack )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  MqttOutputPlugin ( OutputPluginFactory ) :  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -197,6 +208,12 @@ class MqttOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  disco ( self ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . client . loop_stop ( )     # Stop loop   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . client . disconnect ( )    # disconnect  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  info2mqtt ( self ,  mqtt_topic ,  mqtt_data ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        for  mqtt_key  in  mqtt_data :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . client . publish ( f ' { mqtt_topic [ " topic " ] } / { mqtt_key } ' ,  mqtt_data [ mqtt_key ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  store_status ( self ,  response ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -210,13 +227,18 @@ class MqttOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        data  =  response . __dict__ ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        topic  =  params . get ( ' topic ' ,  None )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  not  topic :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            topic  =  f ' { data . get ( " inverter_name " ,  " hoymiles " ) } / { data . get ( " inverter_ser " ,  None ) } '  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            logging . info ( f ' MQTT-topic:  { topic }  data-type:  { type ( response ) } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  isinstance ( response ,  StatusResponse ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            # Global Head  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  data [ ' time ' ]  is  not  None :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					               self . client . publish ( f ' { topic } /time ' ,  data [ ' time ' ] . strftime ( " %d . % m. % y -  % H: % M: % S " ) ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					               self . client . publish ( f ' { topic } /time ' ,  data [ ' time ' ] . strftime ( " %d . % m. % YT % H: % M: % S " ) ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            # AC Data  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            phase_id  =  0  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -234,12 +256,16 @@ class MqttOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            string_id  =  0  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            string_sum_power  =  0  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            for  string  in  data [ ' strings ' ] :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /voltage ' ,  string [ ' voltage ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /current ' ,  string [ ' current ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /power ' ,  string [ ' power ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /YieldDay ' ,  string [ ' energy_daily ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /YieldTotal ' ,  string [ ' energy_total ' ] / 1000 ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_id } /Irradiation ' ,  string [ ' irradiation ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                if  ' name '  in  string :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                    string_name  =  string [ ' name ' ] . replace ( "   " , " _ " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                    string_name  =  string_id  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /voltage ' ,  string [ ' voltage ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /current ' ,  string [ ' current ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /power ' ,  string [ ' power ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /YieldDay ' ,  string [ ' energy_daily ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /YieldTotal ' ,  string [ ' energy_total ' ] / 1000 ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . client . publish ( f ' { topic } /emeter-dc/ { string_name } /Irradiation ' ,  string [ ' irradiation ' ] ,  self . qos ,  self . ret )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                string_id  =  string_id  +  1  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                string_sum_power  + =  string [ ' power ' ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -297,6 +323,9 @@ class VzInverterOutput: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        ts  =  int ( round ( data [ ' time ' ] . timestamp ( )  *  1000 ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            logging . info ( f ' Volkszaehler-Timestamp:  { ts } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # AC Data  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        phase_id  =  0  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        for  phase  in  data [ ' phases ' ] :  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -329,6 +358,7 @@ class VzInverterOutput: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  data [ ' yield_today ' ]  is  not  None :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . try_publish ( ts ,  f ' yield_today ' ,  data [ ' yield_today ' ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . try_publish ( ts ,  f ' efficiency ' ,  data [ ' efficiency ' ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  try_publish ( self ,  ts ,  ctype ,  value ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  not  ctype  in  self . channels :  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -340,9 +370,12 @@ class VzInverterOutput: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        url  =  f ' { self . baseurl } /data/ { uid } .json?operation=add&ts= { ts } &value= { value } '  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  uid  ==  None :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                logging . warnin g( f ' ctype  \" { ctype } \"  has no configured uid-value in ahoy.yml ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                logging . debu g( f ' ctype  \" { ctype } \"  has no configured uid-value in ahoy.yml ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  HOYMILES_DEBUG_LOGGING :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            logging . debug ( f ' VZ-url:  { url } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        try :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            r  =  self . session . get ( url )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  r . status_code  ==  404 :  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -353,6 +386,7 @@ class VzInverterOutput: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					               raise  ValueError ( f ' Transmit result  { url } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        except  ConnectionError  as  e :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            raise  ValueError ( f ' Could not connect VZ-DB  { type ( e ) }   { e . keys ( ) } ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  VolkszaehlerOutputPlugin ( OutputPluginFactory ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ,  config ,  * * params ) :  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -373,13 +407,17 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            exit ( 1 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . session  =  requests . Session ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . inverters  =  dict ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . inverters  =  dict ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        for  inverterconfig  in  config . get ( ' inverters ' ,  [ ] ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            serial  =  inverterconfig . get ( ' serial ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            output  =  VzInverterOutput ( inverterconfig ,  self . session )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . inverters [ serial ]  =  output  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  disco ( self ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . session . close ( )             # closing the connection  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  store_status ( self ,  response ,  * * params ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Publish  StatusResponse  object  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -404,3 +442,4 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                output . store_status ( data ,  self . session )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            except  ValueError  as  e :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                logging . warning ( ' Could not send data to volkszaehler instance:  %s '  %  e )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return