Skip to content

Commit debc079

Browse files
committed
Add support for digital extension plugins.
1 parent b5256ec commit debc079

File tree

2 files changed

+98
-10
lines changed

2 files changed

+98
-10
lines changed

myDevices/devices/digital/__init__.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ def checkDigitalValue(self, value):
3232
if not (value == 0 or value == 1):
3333
raise ValueError("Value %d not in {0, 1}")
3434

35-
36-
#@request("GET", "count")
3735
@response("%d")
3836
def digitalCount(self):
3937
return self.digitalChannelCount
@@ -63,7 +61,6 @@ def getFunction(self, channel):
6361
self.checkDigitalChannel(channel)
6462
return self.__getFunction__(channel)
6563

66-
#@request("GET", "%(channel)d/function")
6764
def getFunctionString(self, channel):
6865
func = self.getFunction(channel)
6966
if func == self.IN:
@@ -80,7 +77,6 @@ def setFunction(self, channel, value):
8077
self.__setFunction__(channel, value)
8178
return self.__getFunction__(channel)
8279

83-
#@request("POST", "%(channel)d/function/%(value)s")
8480
def setFunctionString(self, channel, value):
8581
value = value.lower()
8682
if value == "in":
@@ -93,13 +89,11 @@ def setFunctionString(self, channel, value):
9389
raise ValueError("Bad Function")
9490
return self.getFunctionString(channel)
9591

96-
#@request("GET", "%(channel)d/value")
9792
@response("%d")
9893
def digitalRead(self, channel):
9994
self.checkDigitalChannel(channel)
10095
return self.__digitalRead__(channel)
10196

102-
#@request("GET", "*")
10397
@response(contentType=M_JSON)
10498
def wildcard(self, compact=False):
10599
if compact:
@@ -118,27 +112,24 @@ def wildcard(self, compact=False):
118112
values[i] = {f: func, v: int(self.digitalRead(i))}
119113
return values
120114

121-
#@request("GET", "*/integer")
122115
@response("%d")
123116
def portRead(self):
124117
return self.__portRead__()
125118

126-
#@request("POST", "%(channel)d/value/%(value)d")
127119
@response("%d")
128120
def digitalWrite(self, channel, value):
129121
self.checkDigitalChannel(channel)
130122
self.checkDigitalValue(value)
131123
self.__digitalWrite__(channel, value)
132124
return self.digitalRead(channel)
133125

134-
#@request("POST", "*/integer/%(value)d")
135126
@response("%d")
136127
def portWrite(self, value):
137128
self.__portWrite__(value)
138129
return self.portRead()
139130

131+
140132
DRIVERS = {}
141133
DRIVERS["helper"] = ["DigitalSensor", "DigitalActuator", "LightSwitch", "MotorSwitch", "RelaySwitch", "ValveSwitch", "MotionSensor"]
142-
DRIVERS["mcp23XXX"] = ["MCP23008", "MCP23009", "MCP23017", "MCP23018", "MCP23S08", "MCP23S09", "MCP23S17", "MCP23S18"]
143134
DRIVERS["pcf8574" ] = ["PCF8574", "PCF8574A"]
144135
DRIVERS["ds2408" ] = ["DS2408"]

myDevices/plugins/digital.py

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

0 commit comments

Comments
 (0)