Skip to content

Commit 02a5dbb

Browse files
authored
Merge pull request #21 from myDevicesIoT/development
Development
2 parents 903ce84 + b7ae3d2 commit 02a5dbb

File tree

21 files changed

+679
-470
lines changed

21 files changed

+679
-470
lines changed

myDevices/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""
22
This package contains the Cayenne agent, which is a full featured client for the Cayenne IoT project builder: https://cayenne.mydevices.com. It sends system information as well as sensor and actuator data and responds to actuator messages initiated from the Cayenne dashboard and mobile apps.
33
"""
4-
__version__ = '2.0.2'
4+
__version__ = '2.0.3'
5+

myDevices/cloud/apiclient.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,7 @@ def loginDevice(self, inviteCode):
9898
if response and response.status_code == 200:
9999
return self.getCredentials(response.content)
100100
return None
101+
102+
def getDataTypes(self):
103+
url = '/ui/datatypes'
104+
return self.sendRequest('GET', url)

myDevices/datatypes.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""This module provides a script for getting the available data types and units that can be used with Cayenne."""
2+
3+
import sys
4+
import inspect
5+
from myDevices.cloud.apiclient import CayenneApiClient
6+
7+
if __name__ == "__main__":
8+
args = sys.argv[1:]
9+
if '--help' in args or '-h' in args:
10+
print('Usage: python3 -m myDevices.datatypes [-h] [PATTERN ...]\n\n'
11+
'Search for PATTERN in any of the available Cayenne data types and units.\n'
12+
'If no PATTERN is specified all available data types and units are displayed.\n'
13+
'The case of PATTERN is ignored.\n\n'
14+
'Example: python3 -m myDevices.datatypes temp humidity\n\n'
15+
'Options:\n'
16+
' -h, --help Display this help message and exit')
17+
sys.exit()
18+
api_client = CayenneApiClient('https://api.mydevices.com')
19+
data_types = api_client.getDataTypes().json()
20+
if 'error' in data_types:
21+
print('Error {}. Could not retrieve data types. Please try again later.'.format(data_types['statusCode']))
22+
sys.exit()
23+
output = []
24+
for data_type in data_types:
25+
# Ignore LT100GPS type since that is a custom type that is not intended for general use.
26+
if data_type['data_type'] != 'LT100GPS':
27+
units = ''
28+
for unit in data_type['units']:
29+
payload_unit = unit['payload_unit'] if unit['payload_unit'] else 'null'
30+
units += ('\'{}\' ({}), '.format(payload_unit, unit['unit_label']))
31+
units = units[:-2]
32+
entry = '{}\n Type: \'{}\'\n Units: {}\n'.format(data_type['data_type'], data_type['payload_type'], units)
33+
if not args:
34+
output.append(entry)
35+
else:
36+
for arg in args:
37+
if entry.lower().find(arg.lower()) != -1:
38+
output.append(entry)
39+
output.sort(key=lambda x: x.lower())
40+
for item in output:
41+
print(item)

myDevices/devices/analog/__init__.py

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
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
19+
1820

1921
class ADC():
2022
def __init__(self, channelCount, resolution, vref):
@@ -34,79 +36,72 @@ def checkAnalogValue(self, value):
3436
if not 0 <= value <= self._analogMax:
3537
raise ValueError("Value %d out of range [%d..%d]" % (value, 0, self._analogMax))
3638

37-
#@request("GET", "analog/count")
3839
@response("%d")
3940
def analogCount(self):
4041
return self._analogCount
4142

42-
#@request("GET", "analog/resolution")
4343
@response("%d")
4444
def analogResolution(self):
4545
return self._analogResolution
4646

47-
#@request("GET", "analog/max")
4847
@response("%d")
4948
def analogMaximum(self):
5049
return int(self._analogMax)
5150

52-
#@request("GET", "analog/vref")
5351
@response("%.2f")
5452
def analogReference(self):
5553
return self._analogRef
5654

5755
def __analogRead__(self, channel, diff):
5856
raise NotImplementedError
5957

60-
#@request("GET", "analog/%(channel)d/integer")
6158
@response("%d")
6259
def analogRead(self, channel, diff=False):
6360
self.checkAnalogChannel(channel)
6461
return self.__analogRead__(channel, diff)
6562

66-
#@request("GET", "analog/%(channel)d/float")
6763
@response("%.2f")
6864
def analogReadFloat(self, channel, diff=False):
6965
return self.analogRead(channel, diff) / float(self._analogMax)
7066

71-
#@request("GET", "analog/%(channel)d/volt")
7267
@response("%.2f")
7368
def analogReadVolt(self, channel, diff=False):
7469
if self._analogRef == 0:
7570
raise NotImplementedError
7671
return self.analogReadFloat(channel, diff) * self._analogRef
7772

78-
#@request("GET", "analog/*/integer")
7973
@response(contentType=M_JSON)
8074
def analogReadAll(self):
8175
values = {}
8276
for i in range(self._analogCount):
8377
values[i] = self.analogRead(i)
8478
return values
8579

86-
#@request("GET", "analog/*/float")
8780
@response(contentType=M_JSON)
8881
def analogReadAllFloat(self):
8982
values = {}
9083
for i in range(self._analogCount):
9184
values[i] = float("%.2f" % self.analogReadFloat(i))
9285
return values
9386

94-
#@request("GET", "analog/*/volt")
9587
@response(contentType=M_JSON)
9688
def analogReadAllVolt(self):
9789
values = {}
9890
for i in range(self._analogCount):
9991
values[i] = float("%.2f" % self.analogReadVolt(i))
10092
return values
10193

102-
def read(self, channel, diff=False):
103-
return self.analogRead(channel, diff)
94+
def read(self, channel, value_type=None, diff=False):
95+
read_functions = {'float': self.analogReadFloat, 'volt': self.analogReadVolt}
96+
read_function = read_functions.get(value_type, self.analogRead)
97+
return read_function(channel, diff)
10498

10599
def readFloat(self, channel, diff=False):
106-
return self.analogReadFloat(channel, diff)
100+
return self.analogReadFloat(channel, diff)
107101

108102
def readVolt(self, channel, diff=False):
109-
return self.analogReadVolt(channel, diff)
103+
return self.analogReadVolt(channel, diff)
104+
110105

111106
class DAC(ADC):
112107
def __init__(self, channelCount, resolution, vref):
@@ -118,35 +113,35 @@ def __family__(self):
118113
def __analogWrite__(self, channel, value):
119114
raise NotImplementedError
120115

121-
#@request("POST", "analog/%(channel)d/integer/%(value)d")
122116
@response("%d")
123117
def analogWrite(self, channel, value):
124118
self.checkAnalogChannel(channel)
125119
self.checkAnalogValue(value)
126120
self.__analogWrite__(channel, value)
127121
return self.analogRead(channel)
128122

129-
#@request("POST", "analog/%(channel)d/float/%(value)f")
130123
@response("%.2f")
131124
def analogWriteFloat(self, channel, value):
132125
self.analogWrite(channel, int(value * self._analogMax))
133126
return self.analogReadFloat(channel)
134127

135-
#@request("POST", "analog/%(channel)d/volt/%(value)f")
136128
@response("%.2f")
137129
def analogWriteVolt(self, channel, value):
138130
self.analogWriteFloat(channel, value /self._analogRef)
139131
return self.analogReadVolt(channel)
140132

141-
def write(self, channel, value):
142-
return self.analogWrite(channel, value)
133+
def write(self, channel, value, value_type=None):
134+
write_functions = {'float': self.analogWriteFloat, 'volt': self.analogWriteVolt}
135+
write_function = write_functions.get(value_type, self.analogWrite)
136+
return write_function(channel, value)
143137

144138
def writeFloat(self, channel, value):
145139
return self.analogWriteFloat(channel, value)
146140

147141
def writeVolt(self, channel, value):
148142
return self.analogWriteVolt(channel, value)
149143

144+
150145
class PWM():
151146
def __init__(self, channelCount, resolution, frequency):
152147
self._pwmCount = channelCount
@@ -179,54 +174,51 @@ def __pwmRead__(self, channel):
179174
def __pwmWrite__(self, channel, value):
180175
raise NotImplementedError
181176

182-
#@request("GET", "pwm/count")
183177
@response("%d")
184178
def pwmCount(self):
185179
return self._pwmCount
186180

187-
#@request("GET", "pwm/resolution")
188181
@response("%d")
189182
def pwmResolution(self):
190183
return self._pwmResolution
191184

192-
#@request("GET", "pwm/max")
193185
@response("%d")
194186
def pwmMaximum(self):
195187
return int(self._pwmMax)
196188

197-
#@request("GET", "pwm/%(channel)d/integer")
198189
@response("%d")
199190
def pwmRead(self, channel):
200191
self.checkPWMChannel(channel)
201192
return self.__pwmRead__(channel)
202193

203-
#@request("GET", "pwm/%(channel)d/float")
204194
@response("%.2f")
205195
def pwmReadFloat(self, channel):
206196
return self.pwmRead(channel) / float(self._pwmMax)
207197

208-
#@request("POST", "pwm/%(channel)d/integer/%(value)d")
209198
@response("%d")
210199
def pwmWrite(self, channel, value):
211200
self.checkPWMChannel(channel)
212201
self.checkPWMValue(value)
213202
self.__pwmWrite__(channel, value)
214203
return self.pwmRead(channel)
215204

216-
#@request("POST", "pwm/%(channel)d/float/%(value)f")
217205
@response("%.2f")
218206
def pwmWriteFloat(self, channel, value):
219207
self.pwmWrite(channel, int(value * self._pwmMax))
220208
return self.pwmReadFloat(channel)
221209

222-
def read(self, channel):
223-
return self.pwmRead(channel)
210+
def read(self, channel, value_type=None):
211+
read_functions = {'float': self.pwmReadFloat, 'angle': self.pwmReadAngle}
212+
read_function = read_functions.get(value_type, self.pwmRead)
213+
return read_function(channel)
224214

225215
def readFloat(self, channel):
226216
return self.pwmReadFloat(channel)
227217

228-
def write(self, channel, value):
229-
return self.pwmWrite(channel, value)
218+
def write(self, channel, value, value_type=None):
219+
write_functions = {'float': self.pwmWriteFloat, 'angle': self.pwmWriteAngle}
220+
write_function = write_functions.get(value_type, self.pwmWrite)
221+
return write_function(channel, value)
230222

231223
def writeFloat(self, channel, value):
232224
return self.pwmWriteFloat(channel, value)
@@ -256,7 +248,6 @@ def AngleToRatio(self, value):
256248
f /= self.period
257249
return f
258250

259-
#@request("GET", "pwm/%(channel)d/angle")
260251
@response("%.2f")
261252
def pwmReadAngle(self, channel):
262253
f = self.pwmReadFloat(channel)
@@ -267,7 +258,6 @@ def pwmReadAngle(self, channel):
267258
f = f
268259
return f
269260

270-
#@request("POST", "pwm/%(channel)d/angle/%(value)f")
271261
@response("%.2f")
272262
def pwmWriteAngle(self, channel, value):
273263
if self.reverse[channel]:
@@ -278,7 +268,6 @@ def pwmWriteAngle(self, channel, value):
278268
self.pwmWriteFloat(channel, f)
279269
return self.pwmReadAngle(channel)
280270

281-
#@request("GET", "pwm/*")
282271
@response(contentType=M_JSON)
283272
def pwmWildcard(self):
284273
values = {}
@@ -300,9 +289,7 @@ def writeAngle(self, channel, value):
300289
DRIVERS = {}
301290
DRIVERS["helper"] = ["AnalogSensor", "AnalogActuator", "ServoMotor", "Thermistor", "Photoresistor", "LoadSensor", "DistanceSensor", "LightDimmer"]
302291
DRIVERS["ads1x1x"] = ["ADS1014", "ADS1015", "ADS1114", "ADS1115"]
303-
DRIVERS["mcp3x0x"] = ["MCP3002", "MCP3004", "MCP3008", "MCP3204", "MCP3208"]
304292
DRIVERS["mcp4725"] = ["MCP4725"]
305293
DRIVERS["mcp48XX"] = ["MCP4802", "MCP4812", "MCP4822"]
306294
DRIVERS["mcp492X"] = ["MCP4921", "MCP4922"]
307-
DRIVERS["pca9685"] = ["PCA9685"]
308295
DRIVERS["pcf8591"] = ["PCF8591"]

myDevices/devices/analog/helper.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
from myDevices.utils.types import toint
1717
from myDevices.devices import instance
1818
from myDevices.utils.logger import info
19+
from myDevices.plugins.manager import PluginManager
1920

2021
class AnalogSensor():
2122
def __init__(self, adc, channel):
2223
self.adcname = adc
2324
self.channel = toint(channel)
2425
self.adc = None
26+
self.pluginManager = PluginManager()
2527
self.setADCInstance()
2628

2729
def __str__(self):
@@ -33,32 +35,44 @@ def __family__(self):
3335
def setADCInstance(self):
3436
if not self.adc:
3537
self.adc = instance.deviceInstance(self.adcname)
38+
if not self.adc:
39+
self.adc = self.pluginManager.get_plugin_by_id(self.adcname)
3640

37-
#@request("GET", "integer")
3841
@response("%d")
3942
def read(self):
4043
self.setADCInstance()
41-
return self.adc.analogRead(self.channel)
44+
try:
45+
value = self.adc.analogRead(self.channel)
46+
except:
47+
value = getattr(self.adc['instance'], self.adc['read'])(self.channel)
48+
return value
4249

43-
#@request("GET", "float")
4450
@response("%.2f")
4551
def readFloat(self):
4652
self.setADCInstance()
47-
return self.adc.analogReadFloat(self.channel)
53+
try:
54+
value = self.adc.analogReadFloat(self.channel)
55+
except:
56+
value = getattr(self.adc['instance'], self.adc['read'])(self.channel, 'float')
57+
return value
4858

49-
#@request("GET", "volt")
5059
@response("%.2f")
5160
def readVolt(self):
5261
self.setADCInstance()
53-
return self.adc.analogReadVolt(self.channel)
62+
try:
63+
value = self.adc.analogReadVolt(self.channel)
64+
except:
65+
value = getattr(self.adc['instance'], self.adc['read'])(self.channel, 'volt')
66+
return value
67+
5468

5569
class Photoresistor(AnalogSensor):
5670
def __init__(self, adc, channel):
5771
AnalogSensor.__init__(self, adc, channel)
5872

5973
def __str__(self):
6074
return "Photoresistor"
61-
75+
6276
class Thermistor(AnalogSensor):
6377
def __init__(self, adc, channel):
6478
AnalogSensor.__init__(self, adc, channel)

0 commit comments

Comments
 (0)