forked from victronenergy/velib_python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
settingsdevice.py
118 lines (100 loc) · 4.61 KB
/
settingsdevice.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import dbus
import logging
import time
from functools import partial
# Local imports
from vedbus import VeDbusItemImport
## Indexes for the setting dictonary.
PATH = 0
VALUE = 1
MINIMUM = 2
MAXIMUM = 3
SILENT = 4
## The Settings Device class.
# Used by python programs, such as the vrm-logger, to read and write settings they
# need to store on disk. And since these settings might be changed from a different
# source, such as the GUI, the program can pass an eventCallback that will be called
# as soon as some setting is changed.
#
# The settings are stored in flash via the com.victronenergy.settings service on dbus.
# See https://github.com/victronenergy/localsettings for more info.
#
# If there are settings in de supportSettings list which are not yet on the dbus,
# and therefore not yet in the xml file, they will be added through the dbus-addSetting
# interface of com.victronenergy.settings.
class SettingsDevice(object):
## The constructor processes the tree of dbus-items.
# @param bus the system-dbus object
# @param name the dbus-service-name of the settings dbus service, 'com.victronenergy.settings'
# @param supportedSettings dictionary with all setting-names, and their defaultvalue, min, max and whether
# the setting is silent. The 'silent' entry is optional. If set to true, no changes in the setting will
# be logged by localsettings.
# @param eventCallback function that will be called on changes on any of these settings
# @param timeout Maximum interval to wait for localsettings. An exception is thrown at the end of the
# interval if the localsettings D-Bus service has not appeared yet.
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._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.
self.addSettings(supportedSettings)
logging.debug("===== Settings device init finished =====")
def addSettings(self, settings):
for setting, options in settings.items():
silent = len(options) > SILENT and options[SILENT]
busitem = self.addSetting(options[PATH], options[VALUE],
options[MINIMUM], options[MAXIMUM], silent, callback=partial(self.handleChangedSetting, setting))
self._settings[setting] = busitem
self._values[setting] = busitem.get_value()
def addSetting(self, path, value, _min, _max, silent=False, callback=None):
busitem = VeDbusItemImport(self._bus, self._dbus_name, path, callback)
if busitem.exists and (value, _min, _max, silent) == busitem._proxy.GetAttributes():
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 handleChangedSetting(self, setting, servicename, path, changes):
oldvalue = self._values[setting] if setting in self._values else None
self._values[setting] = changes['Value']
if self._eventCallback is None:
return
self._eventCallback(setting, oldvalue, changes['Value'])
def setDefault(self, path):
item = VeDbusItemImport(self._bus, self._dbus_name, path, createsignal=False)
item.set_default()
def __getitem__(self, setting):
return self._settings[setting].get_value()
def __setitem__(self, setting, newvalue):
result = self._settings[setting].set_value(newvalue)
if result != 0:
# Trying to make some false change to our own settings? How dumb!
assert False