Mercurial > ~darius > hgwebdir.cgi > epro
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 |