def addSetting(self, path, value, _min, _max, silent=False, callback=None): busitem = VeDbusItemImport(self._bus, self._dbus_name, path, callback) if busitem.exists and busitem._proxy.GetSilent() == silent: logging.debug("Setting %s found" % path) else: logging.info("Setting %s does not exist yet or must be adjusted" % path) # Prepare to add the setting. Most dbus types extend the python # type so it is only necessary to additionally test for Int64. if isinstance(value, (int, dbus.Int64)): itemType = 'i' elif isinstance(value, float): itemType = 'f' else: itemType = 's' # Add the setting # TODO, make an object that inherits VeDbusItemImport, and complete the D-Bus settingsitem interface settings_item = VeDbusItemImport(self._bus, self._dbus_name, '/Settings', createsignal=False) setting_path = path.replace('/Settings/', '', 1) if silent: settings_item._proxy.AddSilentSetting('', setting_path, value, itemType, _min, _max) else: settings_item._proxy.AddSetting('', setting_path, value, itemType, _min, _max) busitem = VeDbusItemImport(self._bus, self._dbus_name, path, callback) return busitem
def __init__(self, fpath, bus, serviceName, metrics): self.metrics = metrics self.metric_imports = {} self.metric_values = {} self.bus = bus self.fpath = os.path.join(os.path.dirname(fpath), "by-minute-%s" % os.path.basename(fpath)) if os.path.isfile(fpath): self.tf = TeaFile.openwrite(fpath) else: logging.debug('%s: fields=%s types=%s' % (fpath, ' '.join( [m.name() for m in metrics]), ''.join([m.datatype() for m in metrics]))) now = time.gmtime() self.tf = TeaFile.create(fpath, ' '.join([m.name() for m in metrics]), ''.join([m.datatype() for m in metrics]), serviceName, { 'year': now.tm_year, 'month': now.tm_mon, 'day': now.tm_mday, }) self.startdate = datetime.date( int(self.tf.description.namevalues['year']), int(self.tf.description.namevalues['month']), int(self.tf.description.namevalues['day'])) for m in metrics: logging.debug("Watch %s%s" % (serviceName, m.path())) self.metric_imports[m.path()] = VeDbusItemImport( self.bus, serviceName, m.path(), lambda x, y, z: self.import_value_changed(m, x, y, z)) self.install_update()
def setrelay(self, relayvalue): VeDbusItemImport( bus=self.bus, serviceName=self.DbusServices['CCGXRelay']['Service'], path=self.DbusServices['CCGXRelay']['Path'], eventCallback=None, createsignal=False).set_value(relayvalue)
def setvalues(self, inputpower): VeDbusItemImport( bus=self.bus, serviceName=self.DbusServices['AcSetpoint']['Service'], path=self.DbusServices['AcSetpoint']['Path'], eventCallback=None, createsignal=False).set_value(inputpower)
def _add_setting(self, group, setting, value, type, minimum, maximum, rpc_name='AddSetting'): item = VeDbusItemImport(self._dbus, 'com.victronenergy.settings', '/Settings', createsignal=False) return item._proxy.get_dbus_method(rpc_name)(group, setting, value, type, minimum, maximum)
def add_new_setting_creates_signal(self, rpc_name='AddSetting'): details = { 'group': 'g', 'setting': 's', 'value': 100, 'type': 'i', 'min': 0, 'max': 0 } monitor = VeDbusItemImport(self._dbus, 'com.victronenergy.settings', '/Settings/' + details['group'] + '/' + details['setting'], eventCallback=self._call_me, createsignal=True) self.updateSettingsStamp() self._add_setting(details['group'], details['setting'], details['value'], details['type'], details['min'], details['max']) self.waitForSettingsStored() # restart localsettings self._stopLocalSettings() self._startLocalSettings() # manually iterate the mainloop main_context = GLib.MainContext.default() while main_context.pending(): main_context.iteration(False) self.assertEqual(self._called, [ 'com.victronenergy.settings', '/Settings/' + details['group'] + '/' + details['setting'], { 'Text': '100', 'Value': 100, 'Min': 0, 'Max': 0, 'Default': 100 } ])
def getvalues(self): for service in self.DbusServices: try: self.DbusServices[service]['Value'] = VeDbusItemImport( bus=self.bus, serviceName=self.DbusServices[service]['Service'], path=self.DbusServices[service]['Path'], eventCallback=None, createsignal=False).get_value() # print 'New value of ', self.DbusServices[service]['Value'], 'for', service except dbus.DBusException: print 'Error with DBus' print service try: self.DbusServices[service]['Value'] *= 1 self.DbusServices[service]['Value'] = max(self.DbusServices[service]['Value'], -5000) except: if service == 'L1Power' or service == 'L2Power' or service == 'L3Power': self.DbusServices[service]['Value'] = 0
def test_change_max_creates_signal(self): details = { 'group': 'g', 'setting': 'f', 'value': 103.0, 'type': 'f', 'min': 2.0, 'max': 1002.0 } self._called = [] monitor = VeDbusItemImport(self._dbus, 'com.victronenergy.settings', '/Settings/' + details['group'] + '/' + details['setting'], eventCallback=self._call_me, createsignal=True) self._add_setting(details['group'], details['setting'], details['value'], details['type'], details['min'], details['max']) # manually iterate the mainloop main_context = GLib.MainContext.default() while main_context.pending(): main_context.iteration(False) self.assertEqual(self._called, [ 'com.victronenergy.settings', '/Settings/' + details['group'] + '/' + details['setting'], { 'Default': 103.0, 'Text': '103.0', 'Min': '2.0', 'Max': '1002.0', 'Value': 103 } ])
def add_new_settings_and_readback(self, rpc_name='AddSetting'): from collections import OrderedDict testsets = OrderedDict() testsets['int-no-min-max'] = { 'group': 'g', 'setting': 'in', 'default': 100, 'value': 100, 'type': 'i', 'min': 0, 'max': 0 } testsets['int-with-min-max'] = { 'group': 'g', 'setting': 'iw', 'default': 101, 'value': 101, 'type': 'i', 'min': 0, 'max': 101 } # float-no-min-max doesn't work, because localsettings does not recognize 0.0 and 0.0 as no min max, only 0 and 0 works. # testsets['float-no-min-max'] = {'group': 'g', 'setting': 'f', 'default': 102.0, 'value': 102.0, 'type': 'f', 'min': 0.0, 'max': 0.0} testsets['float-with-min-max'] = { 'group': 'g', 'setting': 'f', 'default': 103.0, 'value': 103.0, 'type': 'f', 'min': 0.0, 'max': 1000.0 } testsets['start-group-with-digit'] = { 'group': '0g', 'setting': 's', 'default': 104, 'value': 104, 'type': 'i', 'min': 0, 'max': 0 } testsets['start-setting-with-digit'] = { 'group': 'g', 'setting': '0s', 'default': 105, 'value': 105, 'type': 'i', 'min': 0, 'max': 0 } testsets['int-re-add-same-min-max'] = { 'group': 'g', 'setting': 'in', 'default': 200, 'value': 100, 'type': 'i', 'min': 0, 'max': 0 } testsets['int-re-add-other-min-max'] = { 'group': 'g', 'setting': 'in', 'default': 201, 'value': 100, 'type': 'i', 'min': 10, 'max': 1000 } testsets['float-re-add-other-min-max'] = { 'group': 'g', 'setting': 'f', 'default': 103.0, 'value': 103.0, 'type': 'f', 'min': 1.0, 'max': 1001.0 } for name, details in testsets.iteritems(): print "\n\n===Testing %s===\n" % name self.updateSettingsStamp() setting = details['setting'] + '/' + rpc_name self.assertEqual( 0, self._add_setting(details['group'], setting, details['default'], details['type'], details['min'], details['max'], rpc_name=rpc_name)) self.waitForSettingsStored() # restart localsettings self._stopLocalSettings() self._startLocalSettings() # read the results i = VeDbusItemImport(self._dbus, 'com.victronenergy.settings', '/Settings/' + details['group'] + '/' + setting, eventCallback=None, createsignal=False) result = copy.deepcopy(details) result['value'] = i.get_value().real result['default'] = i._proxy.GetDefault().real # don't ask me why, but getMin() and getMax() return a string... result['min'] = int( i._proxy.GetMin()) if details['type'] == 'i' else float( i._proxy.GetMin()) result['max'] = int( i._proxy.GetMax()) if details['type'] == 'i' else float( i._proxy.GetMax()) # don't check the type, as there is no GetType() available # result['type'] = i._proxy.GetType() self.assertEqual(details, result)
def _determineservices(self): # batterymeasurement is either 'default' or 'com_victronenergy_battery_288/Dc/0'. # In case it is set to default, we use the AutoSelected battery measurement, given by # SystemCalc. batterymeasurement = None batteryservicename = None newbatteryservice = None batteryprefix = "" selectedbattery = self._settings['batterymeasurement'] vebusservice = None if selectedbattery == 'default': batterymeasurement = self._dbusmonitor.get_value( 'com.victronenergy.system', '/AutoSelectedBatteryMeasurement') elif len(selectedbattery.split( "/", 1)) == 2: # Only very basic sanity checking.. batterymeasurement = self._settings['batterymeasurement'] elif selectedbattery == 'nobattery': batterymeasurement = None else: # Exception: unexpected value for batterymeasurement pass if batterymeasurement: batteryprefix = "/" + batterymeasurement.split("/", 1)[1] # Get the current battery servicename if self._battery_measurement_voltage_import: oldservice = ( self._battery_measurement_voltage_import.serviceName + self._battery_measurement_voltage_import.path.replace( "/Voltage", "")) else: oldservice = None if batterymeasurement: try: batteryservicename = VeDbusItemImport( bus=self._bus, serviceName="com.victronenergy.system", path='/ServiceMapping/' + batterymeasurement.split("/", 1)[0], eventCallback=None, createsignal=False) if batteryservicename.get_value(): newbatteryservice = batteryservicename.get_value( ) + batteryprefix except dbus.exceptions.DBusException: pass else: newbatteryservice = None if batteryservicename and batteryservicename.get_value(): self._battery_measurement_available = True logger.info( 'Battery service we need (%s) found! Using it for generator start/stop' % batterymeasurement) try: self._battery_measurement_voltage_import = VeDbusItemImport( bus=self._bus, serviceName=batteryservicename.get_value(), path=batteryprefix + '/Voltage', eventCallback=None, createsignal=True) self._battery_measurement_current_import = VeDbusItemImport( bus=self._bus, serviceName=batteryservicename.get_value(), path=batteryprefix + '/Current', eventCallback=None, createsignal=True) # Exception caused by Matthijs :), we forgot to batteryprefix the Soc during the big path-change... self._battery_measurement_soc_import = VeDbusItemImport( bus=self._bus, serviceName=batteryservicename.get_value(), path='/Soc', eventCallback=None, createsignal=True) except Exception: logger.debug('Error getting battery service!') self._battery_measurement_voltage_import = None self._battery_measurement_current_import = None self._battery_measurement_soc_import = None elif selectedbattery == 'nobattery' and self._battery_measurement_available: logger.info( 'Battery monitoring disabled! Stop evaluating related conditions' ) self._battery_measurement_voltage_import = None self._battery_measurement_current_import = None self._battery_measurement_soc_import = None self._battery_measurement_available = False elif batteryservicename and batteryservicename.get_value( ) is None and self._battery_measurement_available: logger.info( 'Battery service we need (%s) is not available! Stop evaluating related conditions' % batterymeasurement) self._battery_measurement_voltage_import = None self._battery_measurement_current_import = None self._battery_measurement_soc_import = None self._battery_measurement_available = False # Get the default VE.Bus service and import high temperature and overload warnings try: vebusservice = VeDbusItemImport( bus=self._bus, serviceName="com.victronenergy.system", path='/VebusService', eventCallback=None, createsignal=False) if vebusservice.get_value() and ( vebusservice.get_value() != self._vebusservice or not self._vebusservice_available): self._vebusservice = vebusservice.get_value() self._vebusservice_available = True logger.info( 'Vebus service (%s) found! Using it for generator start/stop' % vebusservice.get_value()) self._vebusservice_high_temperature_import = VeDbusItemImport( bus=self._bus, serviceName=vebusservice.get_value(), path='/Alarms/HighTemperature', eventCallback=None, createsignal=True) self._vebusservice_overload_import = VeDbusItemImport( bus=self._bus, serviceName=vebusservice.get_value(), path='/Alarms/Overload', eventCallback=None, createsignal=True) except Exception: logger.info('Error getting Vebus service!') self._vebusservice_available = False self._vebusservice_high_temperature_import = None self._vebusservice_overload_import = None logger.info( 'Vebus service (%s) dissapeared! Stop evaluating related conditions' % self._vebusservice) # Trigger an immediate check of system status self._changed = True
def _evaluate_if_we_are_needed(self): if self._dbusmonitor.get_value('com.victronenergy.settings', '/Settings/Relay/Function') == 1: if not self._relay_state_import: logger.info('Getting relay from systemcalc.') try: self._relay_state_import = VeDbusItemImport( bus=self._bus, serviceName='com.victronenergy.system', path='/Relay/0/State', eventCallback=None, createsignal=True) except dbus.exceptions.DBusException: logger.info('Systemcalc relay not available.') self._relay_state_import = None pass if self._dbusservice is None: logger.info( 'Action! Going on dbus and taking control of the relay.') relay_polarity_import = VeDbusItemImport( bus=self._bus, serviceName='com.victronenergy.settings', path='/Settings/Relay/Polarity', eventCallback=None, createsignal=True) # As is not possible to keep the relay state during the CCGX power cycles, # set the relay polarity to normally open. if relay_polarity_import.get_value() == 1: relay_polarity_import.set_value(0) logger.info('Setting relay polarity to normally open.') # put ourselves on the dbus self._dbusservice = VeDbusService( 'com.victronenergy.generator.startstop0') self._dbusservice.add_mandatory_paths( processname=__file__, processversion=softwareversion, connection='generator', deviceinstance=0, productid=None, productname=None, firmwareversion=None, hardwareversion=None, connected=1) # State: None = invalid, 0 = stopped, 1 = running self._dbusservice.add_path('/State', value=0) # Condition that made the generator start self._dbusservice.add_path('/RunningByCondition', value='') # Runtime self._dbusservice.add_path('/Runtime', value=0, gettextcallback=self._gettext) # Today runtime self._dbusservice.add_path('/TodayRuntime', value=0, gettextcallback=self._gettext) # Test run runtime self._dbusservice.add_path( '/TestRunIntervalRuntime', value=self._interval_runtime( self._settings['testruninterval']), gettextcallback=self._gettext) # Next tes trun date, values is 0 for test run disabled self._dbusservice.add_path('/NextTestRun', value=None, gettextcallback=self._gettext) # Next tes trun is needed 1, not needed 0 self._dbusservice.add_path('/SkipTestRun', value=None) # Manual start self._dbusservice.add_path('/ManualStart', value=0, writeable=True) # Manual start timer self._dbusservice.add_path('/ManualStartTimer', value=0, writeable=True) # Silent mode active self._dbusservice.add_path('/QuietHours', value=0) self._determineservices() else: if self._dbusservice is not None: self._stop_generator() self._dbusservice.__del__() self._dbusservice = None # Reset conditions for condition in self._condition_stack: self._reset_condition(self._condition_stack[condition]) logger.info( 'Relay function is no longer set to generator start/stop: made sure generator is off ' + 'and now going off dbus') self._relay_state_import = None
def setDefault(self, path): item = VeDbusItemImport(self._bus, self._dbus_name, path, createsignal=False) item.set_default()
def __init__(self, bus, supportedSettings, eventCallback, name='com.victronenergy.settings', timeout=0): logging.debug("===== Settings device init starting... =====") self._bus = bus self._dbus_name = name self._eventCallback = eventCallback self._supportedSettings = supportedSettings self._values = { } # stored the values, used to pass the old value along on a setting change self._settings = {} count = 0 while True: if 'com.victronenergy.settings' in self._bus.list_names(): break if count == timeout: raise Exception( "The settings service com.victronenergy.settings does not exist!" ) count += 1 logging.info('waiting for settings') time.sleep(1) # Add the items. for setting, options in self._supportedSettings.items(): busitem = VeDbusItemImport(self._bus, self._dbus_name, options[PATH], self.handleChangedSetting) silent = len(options) > SILENT and options[SILENT] if busitem.exists and busitem._proxy.GetSilent() == silent: logging.debug("Setting %s found" % options[PATH]) else: logging.info( "Setting %s does not exist yet or must be adjusted" % options[PATH]) # Prepare to add the setting. path = options[PATH].replace('/Settings/', '', 1) value = options[VALUE] if type(value) == int or type(value) == dbus.Int16 or type( value) == dbus.Int32 or type(value) == dbus.Int64: itemType = 'i' elif type(value) == float or type(value) == dbus.Double: itemType = 'f' else: itemType = 's' # Add the setting # TODO, make an object that inherits VeDbusItemImport, and complete the D-Bus settingsitem interface settings_item = VeDbusItemImport(self._bus, self._dbus_name, '/Settings', createsignal=False) if silent: settings_item._proxy.AddSilentSetting( '', path, value, itemType, options[MINIMUM], options[MAXIMUM]) else: settings_item._proxy.AddSetting('', path, value, itemType, options[MINIMUM], options[MAXIMUM]) busitem = VeDbusItemImport(self._bus, self._dbus_name, options[PATH], self.handleChangedSetting) self._settings[setting] = busitem self._values[setting] = busitem.get_value() logging.debug("===== Settings device init finished =====")
def import_value(self, serviceName, path): if serviceName not in self.imported: self.imported[serviceName] = {} if path in self.imported[serviceName]: return self.imported[serviceName][path] = VeDbusItemImport( self.bus, serviceName, path, self.import_value_changed)
from vedbus import VeDbusItemExport, VeDbusItemImport DBusGMainLoop(set_as_default=True) # Connect to the sessionbus. Note that on ccgx we use systembus instead. dbusConn = dbus.SessionBus() if 'DBUS_SESSION_BUS_ADDRESS' in os.environ else dbus.SystemBus() # dictionary containing the different items dbusObjects = {} # check if the vbus.ttyO1 exists (it normally does on a ccgx, and for linux a pc, there is # some emulator. hasVEBus = 'com.victronenergy.vebus.ttyO1' in dbusConn.list_names() dbusObjects['PyString'] = VeDbusItemImport(dbusConn, 'com.victronenergy.example', '/String') if hasVEBus: dbusObjects['C_string'] = VeDbusItemImport(dbusConn, 'com.victronenergy.vebus.ttyO1', '/Mgmt/ProcessName') dbusObjects['PyFloat'] = VeDbusItemImport(dbusConn, 'com.victronenergy.example', '/Float') if hasVEBus: dbusObjects['C_float'] = VeDbusItemImport(dbusConn, 'com.victronenergy.vebus.ttyO1', '/Dc/V') dbusObjects['PyInt'] = VeDbusItemImport(dbusConn, 'com.victronenergy.example', '/Int') if hasVEBus: dbusObjects['C_int'] = VeDbusItemImport(dbusConn, 'com.victronenergy.vebus.ttyO1', '/State') dbusObjects['PyNegativeInt'] = VeDbusItemImport(dbusConn, 'com.victronenergy.example', '/NegativeInt') if hasVEBus: dbusObjects['C_negativeInt'] = VeDbusItemImport(dbusConn, 'com.victronenergy.vebus.ttyO1', '/Dc/I') # print the results print '----' for key, o in dbusObjects.items(): print key + ' at ' + o.serviceName + o.path
'/Fix', '/Position/Latitude', '/Position/Longitude', '/NrOfSatellites', '/Speed', '/Position/Course'] } resp = {} dbusConn = dbus.SessionBus() if 'DBUS_SESSION_BUS_ADDRESS' in os.environ else dbus.SystemBus() for bus,list in query.items(): resp[bus] = {} for path in list: resp[bus][path] = VeDbusItemImport(dbusConn, bus, path).get_value() data = resp[gps] # Set up a client for InfluxDB dbclient = InfluxDBClient(config[influx_server]['host'], config[influx_server]['port'], config[influx_server]['username'], config[influx_server]['password'], config[influx_server]['database']) json_body = [{ "measurement": "gps", "fields": { "alt": float(data['/Altitude']), "lat": float(data['/Position/Latitude']), "lon": float(data['/Position/Longitude']), "sats": float(data['/NrOfSatellites']), "speed": float(data['/Speed']), }
def scan_dbus_service(self, serviceName): newDeviceAdded = False # make it a normal string instead of dbus string serviceName = str(serviceName) for s in self.dbusTree.keys(): if serviceName.split('.')[0:3] == s.split('.')[0:3]: logger.info( "Found: %s matches %s, scanning and storing items" % (serviceName, s)) # we should never be notified to add a D-Bus service that we already have. If this assertion # raises, check process_name_owner_changed, and D-Bus workings. assert serviceName not in self.items service = {} # create the empty list items. whentologoptions = [ 'configChange', 'onIntervalAlwaysAndOnEvent', 'onIntervalOnlyWhenChanged', 'onIntervalAlways' ] # these lists will contain the VeDbusItemImport objects with that whenToLog setting. Used to for whentolog in whentologoptions: service[whentolog] = [] service['paths'] = {} try: # for vebus.ttyO1, this is workaround, since VRM Portal expects the main vebus devices at # instance 0. Not sure how to fix this yet. if serviceName == 'com.victronenergy.vebus.ttyO1' and self.vebusDeviceInstance0: device_instance = 0 else: device_instance = VeDbusItemImport( self.dbusConn, serviceName, '/DeviceInstance', createsignal=False).get_value() device_instance = 0 if device_instance is None else int( device_instance) service['deviceInstance'] = device_instance logger.info(" %s has device instance %s" % (serviceName, service['deviceInstance'])) for path, options in self.dbusTree[s].items(): # path will be the D-Bus path: '/Ac/ActiveIn/L1/V' # options will be a dictionary: {'code': 'V', 'whenToLog': 'onIntervalAlways'} # check that the whenToLog setting is set to something we expect assert options['whenToLog'] is None or options[ 'whenToLog'] in whentologoptions # create and store the VeDbusItemImport. Store it both searchable by names, and in the # relevant whenToLog list. o = VeDbusItemImport(self.dbusConn, serviceName, path, self.handler_value_changes) if options['whenToLog']: service[options['whenToLog']].append(o) service['paths'][path] = { 'dbusObject': o, 'vrmDict': options } logger.debug(" Added %s%s" % (serviceName, path)) # Adjust self at the end of the scan, so we don't have an incomplete set of # data if an exception occurs during the scan. logger.debug("Finished scanning and storing items for %s" % serviceName) self.items[serviceName] = service newDeviceAdded = True except dbus.exceptions.DBusException, e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.Disconnected': logger.info( "Service disappeared while being scanned: %s" % serviceName) else: raise
else: try: goeCharger.setAllowCharging(1) status = goeCharger.setMaxCurrent(i) print("--> %d Ampere gesetzt um %s" % (i, currentTime)) return True except Exception: print("Nicht gesetzt! %s" % i) return False iGoe_old = 0 while True: batteryOffset = args.battery_offset solarPower = VeDbusItemImport(dbusConn, 'com.victronenergy.system', '/Ac/PvOnGrid/L1/Power').get_value() if solarPower == None: solarPower = 0 solarPower = int(solarPower) try: battery_soc = VeDbusItemImport(dbusConn, 'com.victronenergy.battery.ttyO2', '/Soc').get_value() except Exception: print("Konnte SOC nicht bestimmen") batteryOffset += getBatteryOffsetFromFile() if args.goe_ampere > 0: iGoe = args.goe_ampere