comparison velib_python/settingsdevice.py @ 8:9c0435a617db

Import velib_python
author Daniel O'Connor <darius@dons.net.au>
date Sun, 05 Dec 2021 14:35:36 +1030
parents
children
comparison
equal deleted inserted replaced
5:982eeffe9d95 8:9c0435a617db
1 import dbus
2 import logging
3 import time
4 from functools import partial
5
6 # Local imports
7 from vedbus import VeDbusItemImport
8
9 ## Indexes for the setting dictonary.
10 PATH = 0
11 VALUE = 1
12 MINIMUM = 2
13 MAXIMUM = 3
14 SILENT = 4
15
16 ## The Settings Device class.
17 # Used by python programs, such as the vrm-logger, to read and write settings they
18 # need to store on disk. And since these settings might be changed from a different
19 # source, such as the GUI, the program can pass an eventCallback that will be called
20 # as soon as some setting is changed.
21 #
22 # The settings are stored in flash via the com.victronenergy.settings service on dbus.
23 # See https://github.com/victronenergy/localsettings for more info.
24 #
25 # If there are settings in de supportSettings list which are not yet on the dbus,
26 # and therefore not yet in the xml file, they will be added through the dbus-addSetting
27 # interface of com.victronenergy.settings.
28 class SettingsDevice(object):
29 ## The constructor processes the tree of dbus-items.
30 # @param bus the system-dbus object
31 # @param name the dbus-service-name of the settings dbus service, 'com.victronenergy.settings'
32 # @param supportedSettings dictionary with all setting-names, and their defaultvalue, min, max and whether
33 # the setting is silent. The 'silent' entry is optional. If set to true, no changes in the setting will
34 # be logged by localsettings.
35 # @param eventCallback function that will be called on changes on any of these settings
36 # @param timeout Maximum interval to wait for localsettings. An exception is thrown at the end of the
37 # interval if the localsettings D-Bus service has not appeared yet.
38 def __init__(self, bus, supportedSettings, eventCallback, name='com.victronenergy.settings', timeout=0):
39 logging.debug("===== Settings device init starting... =====")
40 self._bus = bus
41 self._dbus_name = name
42 self._eventCallback = eventCallback
43 self._values = {} # stored the values, used to pass the old value along on a setting change
44 self._settings = {}
45
46 count = 0
47 while True:
48 if 'com.victronenergy.settings' in self._bus.list_names():
49 break
50 if count == timeout:
51 raise Exception("The settings service com.victronenergy.settings does not exist!")
52 count += 1
53 logging.info('waiting for settings')
54 time.sleep(1)
55
56 # Add the items.
57 self.addSettings(supportedSettings)
58
59 logging.debug("===== Settings device init finished =====")
60
61 def addSettings(self, settings):
62 for setting, options in settings.items():
63 silent = len(options) > SILENT and options[SILENT]
64 busitem = self.addSetting(options[PATH], options[VALUE],
65 options[MINIMUM], options[MAXIMUM], silent, callback=partial(self.handleChangedSetting, setting))
66 self._settings[setting] = busitem
67 self._values[setting] = busitem.get_value()
68
69 def addSetting(self, path, value, _min, _max, silent=False, callback=None):
70 busitem = VeDbusItemImport(self._bus, self._dbus_name, path, callback)
71 if busitem.exists and (value, _min, _max, silent) == busitem._proxy.GetAttributes():
72 logging.debug("Setting %s found" % path)
73 else:
74 logging.info("Setting %s does not exist yet or must be adjusted" % path)
75
76 # Prepare to add the setting. Most dbus types extend the python
77 # type so it is only necessary to additionally test for Int64.
78 if isinstance(value, (int, dbus.Int64)):
79 itemType = 'i'
80 elif isinstance(value, float):
81 itemType = 'f'
82 else:
83 itemType = 's'
84
85 # Add the setting
86 # TODO, make an object that inherits VeDbusItemImport, and complete the D-Bus settingsitem interface
87 settings_item = VeDbusItemImport(self._bus, self._dbus_name, '/Settings', createsignal=False)
88 setting_path = path.replace('/Settings/', '', 1)
89 if silent:
90 settings_item._proxy.AddSilentSetting('', setting_path, value, itemType, _min, _max)
91 else:
92 settings_item._proxy.AddSetting('', setting_path, value, itemType, _min, _max)
93
94 busitem = VeDbusItemImport(self._bus, self._dbus_name, path, callback)
95
96 return busitem
97
98 def handleChangedSetting(self, setting, servicename, path, changes):
99 oldvalue = self._values[setting] if setting in self._values else None
100 self._values[setting] = changes['Value']
101
102 if self._eventCallback is None:
103 return
104
105 self._eventCallback(setting, oldvalue, changes['Value'])
106
107 def setDefault(self, path):
108 item = VeDbusItemImport(self._bus, self._dbus_name, path, createsignal=False)
109 item.set_default()
110
111 def __getitem__(self, setting):
112 return self._settings[setting].get_value()
113
114 def __setitem__(self, setting, newvalue):
115 result = self._settings[setting].set_value(newvalue)
116 if result != 0:
117 # Trying to make some false change to our own settings? How dumb!
118 assert False