question

laurenceh avatar image
laurenceh asked

How to create a new local setting using com.victronenergy.settings

I am trying to create new local settings to be stored in the persistent configuration file, these setting will be for additional sensors I have added dbus services for.

I am trying to follow the instructions in /opt/victronenergy/localsettings/localsettings.py which say

        ## Dbus method AddSetting.
        # Add a new setting by the given parameters. The object-path must be a group.
        # Example 1: dbus /Settings AddSetting Groupname Settingname 100 i 0 100
        # Example 2: dbus /Settings AddSetting Groupname Settingname '/home/root' s 0 0
        # When the new setting is of type string the minimum and maximum will be ignored.


When I try "dbus /Settings AddSetting Temperature Offset 1 i 0 10"

I get the message:

"org.freedesktop.DBus.Error.NotSupported: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead"

If I try: "dbus -y /Settings AddSetting Temperature Offset 1 i 0 10"

I get:

ValueError: Invalid bus name '/Settings': contains invalid character '/'

What is the correct way to create a new permanent setting?


BMV Battery MonitorVenus OS
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

2 Answers
laurenceh avatar image
laurenceh answered ·

Thanks to help from Jeroen I have completed the persistent storage interface for my temperature and humidity services, here is the completed commented code.

This has been tested on Venus OS 2.54 in September 2020

# =========================== Start of settings interface ================
#  The settings interface handles the persistent storage of changes to settings
#  This should probably be created as a new class extension to the settingDevice object
#  The complexity is because this python service handles temperature and humidity
#  Data for about 6 different service paths so we need keep track of different dBusObjects for each device
#
newSettings = {}     # Used to gather new settings to create/check as each dBus object is created
settingObjects = {}  # Used to identify the dBus object and path for each setting
                     # settingsObjects = {setting: [path,object],}
                     # each setting is the complete string e.g. /Settings/Temperature/4/Scale

settingDefaults = {'/Offset': [0, -10, 10],
                   '/Scale'  : [1.0, -5, 5],
                   '/TemperatureType'   : [0, 0, 3]}

# Values changed in the GUI need to be updated in the settings
# Without this changes made through the GUI change the dBusObject but not the persistent setting
# (as tested in venus OS 2.54 August 2020)
def handle_changed_value(setting, path, value):
    global settings
    # The callback to the handle value changes has been modified by using an anonymous function (lambda)
    # the callback is declared each time a path is added see example here
    # self.add_path(path, 0, writeable=True, onchangecallback = lambda x,y: handle_changed_value(setting,x,y) )
    logging.info(" ".join(("Storing change to setting", setting, str(value) )) )
    settings[setting+path] = value
    return True

# Changes made to settings need to be reflected in the GUI and in the running service
def handle_changed_setting(setting, oldvalue, newvalue):
    logging.info('Setting changed, setting: %s, old: %s, new: %s' % (setting, oldvalue, newvalue))
    [path, object] = settingObjects[setting]
    object[path] = newvalue
    return True

# Add setting is called each time a new service path is created that needs a persistent setting
# If the setting already exists the existing recored is unchanged
# If the setting does not exist it is created when the serviceDevice object is created
def addSetting(base, path, dBusObject):
    global settingObjects
    global newSettings
    global settingDefaults
    setting = base + path
    logging.info(" ".join(("Add setting", setting, str(settingDefaults[path]) )) )
    settingObjects[setting] = [path, dBusObject]             # Record the dBus Object and path for this setting
    newSettings[setting] = [setting] + settingDefaults[path] # Add the setting to the list to be created

# initSettings is called when all the required settings have been added
def initSettings(newSettings):
    global settings

    #settingsDevice is the library class that handles the reading and setting of persistent settings
    settings = SettingsDevice(
        bus=dbus.SystemBus() if (platform.machine() == 'armv7l') else dbus.SessionBus(),
        supportedSettings = newSettings,
        eventCallback     = handle_changed_setting)

# readSettings is called after init settings to read all the stored settings and
# set the initial values of each of the service object paths
# Note you can not read or set a setting if it has not be included in the newSettings
#      list passed to create the new settingsDevice class object

def readSettings(list):
    global settings
    for setting in list:
        [path, object] = list[setting]
        logging.info(" ".join(("Retrieved setting", setting, path, str(settings[setting]))))
        object[path] = settings[setting]
# =========================== end of settings interface ======================



2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

jeroen avatar image
jeroen answered ·

That comment is simply wrong, https://github.com/victronenergy/localsettings has the correct ones.

3 comments
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

laurenceh avatar image laurenceh commented ·

Many thanks, I’ll try it out on Monday.

0 Likes 0 ·
laurenceh avatar image laurenceh commented ·

Jerone

I have tried this and made some progress but in doing so have made some setting I would now like to delete.

Two Questions

(1) this done not make it clear how you set the type of a value when you create a setting (i.e. i, f or s).

settings = SettingsDevice(    
bus=dbus.SystemBus() if (platform.machine() == 'armv7l') else dbus.SessionBus(),    
supportedSettings={ 
'loggingenabled': ['/Settings/Logscript/Enabled', 1, 0, 1],
'proxyaddress': ['/Settings/Logscript/Http/Proxy', '', 0, 0],
'proxyport': ['/Settings/Logscript/Http/ProxyPort', '', 0, 0],

What is the correct way to set the type ?

(2)

As I have made a setting with a type 'i' and need to delete it to change the type to 'f'

I don't understand this instruction for remove setting:

dbus com.victronenergy.settings /Settings RemoveSettings '%["Int", "Float", "String"]'

Where is the name of the setting to be removed supposed to go?

I tried:

dbus -y com.victronenergy.settings /Settings/Temperature/3/Scale RemoveSettings 
or
dbus -y com.victronenergy.settings /Settings/Temperature/3/Scale RemoveSettings '%["Int", "Float", "String"]'

The error is

    ret = obj.object.get_dbus_method(method.name, iface.name)(*args)
AttributeError: 'NoneType' object has no attribute 'name'


Thanks for any help

0 Likes 0 ·
jeroen avatar image jeroen ♦ laurenceh commented ·

1) see https://github.com/victronenergy/velib_python/blob/master/settingsdevice.py#L69, the python code will use the type of the (default) value.

2) untested, it should be something like:

dbus -y com.victronenergy.settings /Settings RemoveSettings '%["Temperature/3/Scale"]'
1 Like 1 ·