annotate velib_python/test/mock_dbus_monitor.py @ 14:60ead9b5fc1b

Mark temperature as invalid when <-20C as per spec. Shows up as -25C on the unit I have when the sensor is not connected.
author Daniel O'Connor <darius@dons.net.au>
date Mon, 06 Dec 2021 11:26:20 +1030
parents 9c0435a617db
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
8
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 import dbus
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2 from collections import defaultdict
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 from functools import partial
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 # Simulation a DbusMonitor object, without using the D-Bus (intended for unit tests). Instead of changes values
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 # on the D-Bus you can use the set_value function. set_value will automatically expand the service list. Note
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 # that all simulated D-Bus paths passed to set_value must be part of the dbusTree passed to the constructor of
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 # the monitor.
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 class MockDbusMonitor(object):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 def __init__(self, dbusTree, valueChangedCallback=None, deviceAddedCallback=None,
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 deviceRemovedCallback=None, mountEventCallback=None, vebusDeviceInstance0=False, checkPaths=True):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 self._services = {}
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 self._tree = {}
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 self._seen = defaultdict(set)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 self._watches = defaultdict(dict)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 self._checkPaths = checkPaths
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 self._value_changed_callback = valueChangedCallback
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 self._device_removed_callback = deviceRemovedCallback
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 self._device_added_callback = deviceAddedCallback
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 for s, sv in dbusTree.items():
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 service = self._tree.setdefault(s, set())
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 service.update(['/Connected', '/ProductName', '/Mgmt/Connection', '/DeviceInstance'])
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 for p in sv:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 service.add(p)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 # Gets the value for a certain servicename and path, returns the default_value when
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 # request service and objectPath combination does not not exists or when it is invalid
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 def get_value(self, serviceName, objectPath, default_value=None):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 item = self._get_item(serviceName, objectPath)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 if item is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 return default_value
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 r = item.get_value()
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33 return default_value if r is None else r
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 def _get_item(self, serviceName, objectPath):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36 service = self._services.get(serviceName)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 if service is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 return None
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 if objectPath not in self._tree[_class_name(serviceName)]:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40 return None
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 item = service.get(objectPath)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42 if item is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43 item = MockImportItem(None, valid=False)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 service[objectPath] = item
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45 return item
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 def exists(self, serviceName, objectPath):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 if serviceName not in self._services:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 return False
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 if objectPath not in self._tree[_class_name(serviceName)]:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51 return False
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 return True
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 def set_seen(self, serviceName, path):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 self._seen[serviceName].add(path)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 def seen(self, serviceName, objectPath):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58 return objectPath in self._seen[serviceName]
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 # returns a dictionary, keys are the servicenames, value the instances
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 # optionally use the classfilter to get only a certain type of services, for
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62 # example com.victronenergy.battery.
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 def get_service_list(self, classfilter=None):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 r = {}
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 for servicename,items in self._services.items():
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 if not classfilter or _class_name(servicename) == classfilter:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 item = items.get('/DeviceInstance')
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68 r[servicename] = None if item is None else item.get_value()
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 return r
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 def add_value(self, service, path, value):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 class_name = _class_name(service)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 s = self._tree.get(class_name, None)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74 if s is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 raise Exception('service not found')
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 if self._checkPaths and path not in s:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 raise Exception('Path not found: {}{} (check dbusTree passed to __init__)'.format(service, path))
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78 s = self._services.setdefault(service, {})
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79 s[path] = MockImportItem(value)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 self.set_seen(service, path)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 def set_value(self, serviceName, objectPath, value):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 item = self._get_item(serviceName, objectPath)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 if item is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 return -1
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86 item.set_value(value)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87 self.set_seen(serviceName, objectPath)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88 if self._value_changed_callback != None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 self._value_changed_callback(serviceName, objectPath, None, None, None)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 if serviceName in self._watches:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 if objectPath in self._watches[serviceName]:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 self._watches[serviceName][objectPath]({'Value': value, 'Text': str(value)})
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 elif None in self._watches[serviceName]:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 self._watches[serviceName][None]({'Value': value, 'Text': str(value)})
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95 return 0
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 def set_value_async(self, serviceName, objectPath, value,
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 reply_handler=None, error_handler=None):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99 item = self._get_item(serviceName, objectPath)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 if item is not None and item.exists:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 item.set_value(value)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 if reply_handler is not None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 reply_handler(0)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105 return
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 if error_handler is not None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 error_handler(TypeError('Service or path not found, '
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 'service=%s, path=%s' % (serviceName, objectPath)))
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 def add_service(self, service, values):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 if service in self._services:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 raise Exception('Service already exists: {}'.format(service))
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 self._services[service] = {}
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 for k,v in values.items():
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116 self.add_value(service, k, v)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 if self._device_added_callback != None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118 self._device_added_callback(service, values.get('/DeviceInstance', 0))
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 def remove_service(self, service):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 s = self._services.get(service)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 if s is None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 return
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124 item = s.get('/DeviceInstance')
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125 instance = 0 if item is None else item.get_value()
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 for item in s.values():
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 item.set_service_exists(False)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128 self._services.pop(service)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 if self._device_removed_callback != None:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 self._device_removed_callback(service, instance)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 if service in self._watches:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 del self._watches[service]
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134 def track_value(self, serviceName, objectPath, callback, *args, **kwargs):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 self._watches[serviceName][objectPath] = partial(callback, *args, **kwargs)
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 @property
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138 def dbusConn(self):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139 raise dbus.DBusException("No Connection")
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
142 class MockImportItem(object):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 def __init__(self, value, valid=True, service_exists=True):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 self._value = value
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 self._valid = valid
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
146 self._service_exists = service_exists
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
148 def set_service_exists(self, service_exists):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 self._service_exists = service_exists
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151 def get_value(self):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152 return self._value
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154 @property
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155 def exists(self):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156 return self._valid
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158 def set_value(self, value):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159 if not self._service_exists:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 raise dbus.exceptions.DBusException('org.freedesktop.DBus.Error.ServiceUnknown')
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161 if not self._valid:
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162 raise dbus.exceptions.DBusException('org.freedesktop.DBus.Error.UnknownObject')
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163 self._value = value
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166 def _class_name(service):
9c0435a617db Import velib_python
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167 return '.'.join(service.split('.')[:3])