Skip to content

Commit 9bd0436

Browse files
committed
Add analog and PWM reading and writing.
1 parent debc079 commit 9bd0436

File tree

4 files changed

+174
-36
lines changed

4 files changed

+174
-36
lines changed

myDevices/devices/analog/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from myDevices.decorators.rest import request, response
1616
from myDevices.utils.types import toint, M_JSON
1717
from myDevices.devices import instance
18+
from myDevices.utils.logger import info
1819

1920

2021
class ADC():
@@ -91,8 +92,8 @@ def analogReadAllVolt(self):
9192
return values
9293

9394
def read(self, channel, data_type=None, diff=False):
94-
read_functions = {'float': self.analogReadFloat,'f': self.analogReadFloat,
95-
'volt': self.analogReadVolt,'v': self.analogReadVolt}
95+
read_functions = {'float': self.analogReadFloat, 'f': self.analogReadFloat,
96+
'volt': self.analogReadVolt, 'v': self.analogReadVolt}
9697
read_function = read_functions.get(data_type, self.analogRead)
9798
return read_function(channel, diff)
9899

@@ -205,14 +206,18 @@ def pwmWriteFloat(self, channel, value):
205206
self.pwmWrite(channel, int(value * self._pwmMax))
206207
return self.pwmReadFloat(channel)
207208

208-
def read(self, channel):
209-
return self.pwmRead(channel)
209+
def read(self, channel, data_type=None):
210+
read_functions = {'float': self.pwmReadFloat, 'angle': self.pwmReadAngle}
211+
read_function = read_functions.get(data_type, self.pwmRead)
212+
return read_function(channel)
210213

211214
def readFloat(self, channel):
212215
return self.pwmReadFloat(channel)
213216

214-
def write(self, channel, value):
215-
return self.pwmWrite(channel, value)
217+
def write(self, channel, value, data_type=None):
218+
write_functions = {'float': self.pwmWriteFloat, 'angle': self.pwmWriteAngle}
219+
write_function = write_functions.get(data_type, self.pwmWrite)
220+
return write_function(channel, value)
216221

217222
def writeFloat(self, channel, value):
218223
return self.pwmWriteFloat(channel, value)

myDevices/plugins/analog.py

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,20 @@
11
"""
2-
This module provides classes for interfacing with analog plugins.
2+
This module provides classes for interfacing with analog and PWM plugins.
33
"""
4-
from myDevices.plugins.manager import PluginManager
4+
from myDevices.plugins.io import InputOutput
55
from myDevices.utils.logger import info, debug
66

77

8-
class AnalogInput():
9-
"""Reads data from an analog input."""
8+
class AnalogInput(InputOutput):
9+
"""Reads data from an analog or PWM plugin input."""
1010

11-
def __init__(self, adc):
12-
"""Initializes the analog input.
11+
def __init__(self, plugin_id):
12+
"""Initializes the plugin input.
1313
1414
Arguments:
15-
adc: Analog-to-digital converter plugin ID in the format 'plugin_name:section', e.g. 'cayenne-mcp3xxx:MCP'
16-
"""
17-
self.adc_name = adc
18-
self.adc = None
19-
self.read_args = {}
20-
self.plugin_manager = PluginManager()
21-
self.set_adc()
22-
23-
def set_adc(self):
24-
"""Sets the ADC plugin."""
25-
if not self.adc:
26-
self.adc = self.plugin_manager.get_plugin_by_id(self.adc_name)
27-
self.read_args = self.plugin_manager.get_args(self.adc, 'read_args')
28-
29-
def read_value(self, channel, data_type=None):
30-
"""Read the data value on the specified channel."""
31-
self.set_adc()
32-
try:
33-
value = getattr(self.adc['instance'], self.adc['read'])(channel, data_type=data_type, **self.read_args)
34-
except ValueError as e:
35-
debug(e)
36-
value = None
37-
return value
15+
plugin_id: Plugin ID in the format 'plugin_name:section', e.g. 'cayenne-pca9685:PCA9685'
16+
"""
17+
InputOutput.__init__(self, plugin_id, 'analog', 'in')
3818

3919
def read_float(self, channel):
4020
"""Read the float value on the specified channel."""
@@ -43,3 +23,45 @@ def read_float(self, channel):
4323
def read_volt(self, channel):
4424
"""Read the voltage on the specified channel."""
4525
return self.read_value(channel, 'volt')
26+
27+
def read_angle(self, channel):
28+
"""Read the angle on the specified channel."""
29+
return self.read_value(channel, 'angle')
30+
31+
32+
class AnalogIO(AnalogInput):
33+
"""Reads/writes data from an analog or PWM plugin input/output."""
34+
35+
def __init__(self, plugin_id, function):
36+
"""Initializes the plugin input/output.
37+
38+
Arguments:
39+
plugin_id: Plugin ID in the format 'plugin_name:section', e.g. 'cayenne-pca9685:PCA9685'
40+
function: The pin function, 'in' if the pin is an input, 'out' if it is an output
41+
"""
42+
InputOutput.__init__(self, plugin_id, 'analog', function)
43+
44+
def write_float(self, value, channel):
45+
"""Write the float value on the specified channel."""
46+
return self.write_value(value, channel, 'float')
47+
48+
def write_volt(self, value, channel):
49+
"""Write the voltage on the specified channel."""
50+
return self.write_value(value, channel, 'volt')
51+
52+
def write_angle(self, value, channel):
53+
"""Write the angle on the specified channel."""
54+
return self.write_value(value, channel, 'angle')
55+
56+
57+
class AnalogOutput(AnalogIO):
58+
"""Reads/writes data from an analog or PWM plugin input/output."""
59+
60+
def __init__(self, plugin_id):
61+
"""Initializes the plugin input/output.
62+
63+
Arguments:
64+
plugin_id: Plugin ID in the format 'plugin_name:section', e.g. 'cayenne-pca9685:PCA9685'
65+
"""
66+
AnalogIO.__init__(self, plugin_id, 'out')
67+

myDevices/plugins/io.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
This module provides a class for interfacing with digital, analog and PWM plugins.
3+
"""
4+
from myDevices.plugins.manager import PluginManager
5+
from myDevices.utils.logger import debug, info, exception
6+
7+
8+
class InputOutput():
9+
"""Reads/writes data from a digital, analog or PWM input/output plugin."""
10+
DATA_TYPES = {'digital': {'in': 'digital_sensor', 'out':'digital_actuator'},
11+
'analog': {'in': 'analog_sensor', 'out': 'analog_actuator'}}
12+
13+
def __init__(self, plugin_id, io_type, function):
14+
"""Initializes the analog input/output.
15+
16+
Arguments:
17+
plugin_id: Extension plugin ID in the format 'plugin_name:section', e.g. 'cayenne-pca9685:PCA9685'
18+
io_type: The type of IO, 'analog' or 'digital'
19+
function: The pin function, 'in' if the pin is an input, 'out' if it is an output
20+
"""
21+
self.plugin_id = plugin_id
22+
self.plugin = None
23+
self.io_type = io_type.lower()
24+
self.function = function.lower()
25+
self.current_functions = {}
26+
self.read_args = {}
27+
self.write_args = {}
28+
self.plugin_manager = PluginManager()
29+
self.set_plugin()
30+
31+
def set_plugin(self):
32+
"""Sets the plugin_id plugin."""
33+
if not self.plugin:
34+
self.plugin = self.plugin_manager.get_plugin_by_id(self.plugin_id)
35+
try:
36+
self.read_args = self.plugin_manager.get_args(self.plugin, 'read_args')
37+
self.write_args = self.plugin_manager.get_args(self.plugin, 'write_args')
38+
except:
39+
pass
40+
41+
def set_function(self, channel):
42+
"""Sets the input/output function."""
43+
try:
44+
if self.plugin and (channel not in self.current_functions or self.function != self.current_functions[channel]):
45+
function = getattr(self.plugin['instance'], self.plugin['set_function'])(channel, self.function).lower()
46+
self.current_functions[channel] = function
47+
if function == 'in':
48+
try:
49+
debug('Register callback for channel {}'.format(channel))
50+
getattr(self.plugin['instance'], self.plugin['register_callback'])(channel, self.data_changed, data=channel)
51+
except:
52+
debug('Unable to register callback for channel {}'.format(channel))
53+
pass
54+
except:
55+
debug('Error setting function')
56+
57+
def to_tuple(self, value):
58+
"""Converts value to tuple with the appropriate data type."""
59+
try:
60+
return (value, InputOutput.DATA_TYPES[self.io_type][self.function])
61+
except:
62+
return value
63+
64+
def read(self, channel, data_type=None):
65+
"""Gets the data value for the channel as a tuple with the type."""
66+
return self.to_tuple(self.read_value(channel, data_type))
67+
68+
def read_value(self, channel, data_type=None):
69+
"""Read the data value on the specified channel."""
70+
self.set_plugin()
71+
self.set_function(channel)
72+
result = None
73+
try:
74+
result = getattr(self.plugin['instance'], self.plugin['read'])(channel, data_type=data_type, **self.read_args)
75+
except:
76+
info('Error reading value from plugin {}, channel {}, {}'.format(self.plugin_id, channel, self.plugin))
77+
return result
78+
79+
def write(self, value, channel, data_type=None):
80+
"""Write the digital value for the channel."""
81+
info('IO write, value {}, channel {}'.format(value, channel))
82+
return self.write_value(value, channel, data_type)
83+
84+
def write_value(self, value, channel, data_type=None):
85+
"""Write the data value on the specified channel."""
86+
self.set_plugin()
87+
self.set_function(channel)
88+
result = None
89+
try:
90+
result = getattr(self.plugin['instance'], self.plugin['write'])(channel, value, data_type=data_type, **self.write_args)
91+
except ValueError as e:
92+
debug(e)
93+
return result
94+
95+
def register_callback(self, callback):
96+
"""Register a callback for data changes."""
97+
info('Registering callback: {}'.format(callback))
98+
self.callback = callback
99+
100+
def unregister_callback(self):
101+
"""Register a callback for data changes."""
102+
self.callback = None
103+
104+
def data_changed(self, channel, value):
105+
"""Callback that is called when data has changed."""
106+
if self.callback:
107+
self.callback(self.to_tuple(value))

myDevices/plugins/manager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ def write_value(self, plugin, channel, value):
203203
write_function = getattr(self.plugins[actuator]['instance'], self.plugins[actuator]['write'])
204204
write_args = self.get_args(self.plugins[actuator], 'write_args')
205205
write_function(float(value), **write_args)
206-
except:
206+
except KeyError as e:
207+
error('Error writing value, missing key: {}'.format(e))
208+
return False
209+
except Exception as e:
210+
error('Error writing value: {}'.format(e))
207211
return False
208212
else:
209213
return False

0 commit comments

Comments
 (0)