2022-08-09 21:44:59 +00:00
#!/usr/bin/env python
2022-08-19 21:03:53 +00:00
# import normal packages
import platform
2022-08-09 21:44:59 +00:00
import logging
import sys
import os
2022-08-19 21:03:53 +00:00
import sys
if sys . version_info . major == 2 :
import gobject
else :
from gi . repository import GLib as gobject
import sys
import time
2022-08-09 21:44:59 +00:00
import requests # for http GET
2022-08-19 21:03:53 +00:00
# our own packages from victron
sys . path . insert ( 1 , os . path . join ( os . path . dirname ( __file__ ) , ' /opt/victronenergy/dbus-systemcalc-py/ext/velib_python ' ) )
2022-08-09 21:44:59 +00:00
from vedbus import VeDbusService
2022-08-19 21:03:53 +00:00
class NodeRedMeterTemperature :
def __init__ ( self , servicename , deviceinstance , paths , productname = ' External temp sensor ' , connection = ' Node RED HTTP JSON service ' ) :
self . _dbusservice = VeDbusService ( " {} .http_ {:02d} " . format ( servicename , deviceinstance ) )
2022-08-09 21:44:59 +00:00
self . _paths = paths
2022-08-19 21:03:53 +00:00
2022-08-09 21:44:59 +00:00
logging . debug ( " %s /DeviceInstance = %d " % ( servicename , deviceinstance ) )
2022-08-19 21:03:53 +00:00
2022-08-09 21:44:59 +00:00
# Create the management objects, as specified in the ccgx dbus-api document
self . _dbusservice . add_path ( ' /Mgmt/ProcessName ' , __file__ )
2022-08-19 21:03:53 +00:00
self . _dbusservice . add_path ( ' /Mgmt/ProcessVersion ' , ' Python ' + platform . python_version ( ) )
2022-08-09 21:44:59 +00:00
self . _dbusservice . add_path ( ' /Mgmt/Connection ' , connection )
2022-08-19 21:03:53 +00:00
2022-08-09 21:44:59 +00:00
# Create the mandatory objects
self . _dbusservice . add_path ( ' /DeviceInstance ' , deviceinstance )
2022-08-19 21:14:50 +00:00
self . _dbusservice . add_path ( ' /ProductId ' , 0xA162 ) #from dbus spy with wire attached sensor
2022-08-19 21:03:53 +00:00
self . _dbusservice . add_path ( ' /FilterLength ' , 10 )
self . _dbusservice . add_path ( ' /Offset ' , 0 )
self . _dbusservice . add_path ( ' /Scale ' , 1 )
2022-08-09 21:44:59 +00:00
self . _dbusservice . add_path ( ' /ProductName ' , productname )
2022-08-19 21:03:53 +00:00
self . _dbusservice . add_path ( ' /CustomName ' , " Temperatur Außen " )
self . _dbusservice . add_path ( ' /TemperatureType ' , 2 ) # 0=battery; 1=fridge; 2=generic
2022-08-09 21:44:59 +00:00
self . _dbusservice . add_path ( ' /FirmwareVersion ' , 1.0 )
self . _dbusservice . add_path ( ' /HardwareVersion ' , 0 )
self . _dbusservice . add_path ( ' /Connected ' , 1 )
2022-08-19 21:03:53 +00:00
self . _dbusservice . add_path ( ' /Serial ' , 1337 )
self . _dbusservice . add_path ( ' /UpdateIndex ' , 0 )
# add path values to dbus
2022-08-09 21:44:59 +00:00
for path , settings in self . _paths . items ( ) :
self . _dbusservice . add_path (
2022-08-19 21:03:53 +00:00
path , settings [ ' initial ' ] , gettextcallback = settings [ ' textformat ' ] , writeable = True , onchangecallback = self . _handlechangedvalue )
# last update
self . _lastUpdate = 0
# add _update function 'timer'
2022-08-09 21:44:59 +00:00
gobject . timeout_add ( 2000 , self . _update ) # pause 2000ms before the next request
2022-08-19 21:03:53 +00:00
2022-08-19 21:17:54 +00:00
# add _Status 'timer' to get feedback in log every 5minutes
gobject . timeout_add ( self . _getStatusInterval ( ) * 60 * 1000 , self . _Status )
2022-08-19 21:03:53 +00:00
2022-08-19 21:17:54 +00:00
def _getStatusInterval ( self ) :
2022-08-19 21:03:53 +00:00
value = 1
if not value :
value = 0
return int ( value )
def _getNodeRedData ( self ) :
URL = " http://localhost:1880/temps "
temperature_r = requests . get ( url = URL )
# check for response
if not temperature_r :
raise ConnectionError ( " No response from NodeRed - %s " % ( URL ) )
meter_data = temperature_r . json ( )
# check for Json
if not meter_data :
raise ValueError ( " Converting response to JSON failed " )
return meter_data
2022-08-19 21:17:54 +00:00
def _Status ( self ) :
2022-08-19 21:14:50 +00:00
logging . info ( " Last _update: %s " % ( self . _lastUpdate ) )
2022-08-19 21:03:53 +00:00
logging . info ( " Last ' /Temperature ' : %s " % ( self . _dbusservice [ ' /Temperature ' ] ) )
return True
def _update ( self ) :
2022-08-09 21:44:59 +00:00
try :
2022-08-19 21:03:53 +00:00
#get data from NodeRed 3em
meter_data = self . _getNodeRedData ( )
#send data to DBus
self . _dbusservice [ ' /Temperature ' ] = meter_data [ ' outside ' ]
#logging
logging . debug ( " Temperature Outside (/Temperature): %s " % ( self . _dbusservice [ ' /Temperature ' ] ) )
logging . debug ( " --- " ) ;
# increment UpdateIndex - to show that new data is available
index = self . _dbusservice [ ' /UpdateIndex ' ] + 1 # increment index
if index > 255 : # maximum value of the index
index = 0 # overflow from 255 to 0
self . _dbusservice [ ' /UpdateIndex ' ] = index
#update lastupdate vars
self . _lastUpdate = time . time ( )
except Exception as e :
logging . critical ( ' Error at %s ' , ' _update ' , exc_info = e )
# return true, otherwise add_timeout will be removed from GObject - see docs http://library.isr.ist.utl.pt/docs/pygtk2reference/gobject-functions.html#function-gobject--timeout-add
2022-08-09 21:44:59 +00:00
return True
2022-08-19 21:03:53 +00:00
2022-08-09 21:44:59 +00:00
def _handlechangedvalue ( self , path , value ) :
logging . debug ( " someone else updated %s to %s " % ( path , value ) )
return True # accept the change
2022-08-19 21:03:53 +00:00
2022-08-09 21:44:59 +00:00
2022-08-19 21:03:53 +00:00
def main ( ) :
#configure logging
logging . basicConfig ( format = ' %(asctime)s , %(msecs)d %(name)s %(levelname)s %(message)s ' ,
datefmt = ' % Y- % m- %d % H: % M: % S ' ,
level = logging . INFO ,
handlers = [
logging . FileHandler ( " %s /current.log " % ( os . path . dirname ( os . path . realpath ( __file__ ) ) ) ) ,
logging . StreamHandler ( )
] )
try :
logging . info ( " Start " ) ;
from dbus . mainloop . glib import DBusGMainLoop
# Have a mainloop, so we can send/receive asynchronous calls to and from dbus
DBusGMainLoop ( set_as_default = True )
#formatting
_celcius = lambda p , v : ( str ( round ( v , 2 ) ) + ' °C ' )
#start our main-service
pvac_output = NodeRedMeterTemperature (
servicename = ' com.victronenergy.temperature ' ,
deviceinstance = 18 ,
paths = {
' /Temperature ' : { ' initial ' : 0 , ' textformat ' : _celcius } ,
} )
logging . info ( ' Connected to dbus, and switching over to gobject.MainLoop() (= event based) ' )
mainloop = gobject . MainLoop ( )
mainloop . run ( )
except Exception as e :
logging . critical ( ' Error at %s ' , ' main ' , exc_info = e )
2022-08-09 21:44:59 +00:00
if __name__ == " __main__ " :
main ( )