comparison service/arduinoNode/devices.py @ 971:fbe72d44f15a

only recompile if the C code is new. redo Device class api. single temperature sensor is working Ignore-this: e78106d25dbb2ac8c5e5d8a81d576358 darcs-hash:20150411084359-312f9-7c50d2f4f21dd9d5a0fa8913873a1e6d7d325118
author drewp <drewp@bigasterisk.com>
date Sat, 11 Apr 2015 01:43:59 -0700
parents 70a5392b24d3
children d228105749ac
comparison
equal deleted inserted replaced
970:4f5825a9fc47 971:fbe72d44f15a
1 from rdflib import Namespace, RDF, URIRef 1 from rdflib import Namespace, RDF, URIRef, Literal
2 2
3 ROOM = Namespace('http://projects.bigasterisk.com/room/') 3 ROOM = Namespace('http://projects.bigasterisk.com/room/')
4 4
5 class BoardInput(object): 5 def readLine(read):
6 """ 6 buf = ''
7 one device that gives us input. this includes processing to make 7 for c in iter(lambda: read(1), '\n'):
8 statements, but this object doesn't store state 8 buf += c
9 """ 9 return buf
10 def __init__(self, graph, uri): 10
11 class DeviceType(object):
12 deviceType = None
13 @classmethod
14 def findInstances(cls, graph, board):
15 """
16 return any number of instances of this class for all the separately
17 controlled devices on the board. Two LEDS makes two instances,
18 but two sensors on the same onewire bus makes only one device
19 (which yields more statements).
20 """
21 instances = []
22 for row in graph.query("""SELECT ?dev ?pinNumber WHERE {
23 ?board :hasPin ?pin .
24 ?pin :pinNumber ?pinNumber;
25 :connectedTo ?dev .
26 ?dev a ?thisType .
27 } ORDER BY ?dev""",
28 initBindings=dict(board=board,
29 thisType=cls.deviceType),
30 initNs={'': ROOM}):
31 instances.append(cls(graph, row.dev, int(row.pinNumber)))
32 return instances
33
34 # subclasses may add args to this
35 def __init__(self, graph, uri, pinNumber):
11 self.graph, self.uri = graph, uri 36 self.graph, self.uri = graph, uri
37 self.pinNumber = pinNumber
12 38
13 def readFromPoll(self, read): 39 def readFromPoll(self, read):
14 """ 40 """
15 read an update message returned as part of a poll bundle. This may 41 read an update message returned as part of a poll bundle. This may
16 consume a varying number of bytes depending on the type of 42 consume a varying number of bytes depending on the type of
17 input (e.g. IR receiver). 43 input (e.g. IR receiver).
18 Returns rdf statements. 44 Returns rdf statements.
19 """ 45 """
20 raise NotImplementedError 46 raise NotImplementedError('readFromPoll in %s' % self.__class__)
21 47
48 def generateIncludes(self):
49 return []
50
51 def generateArduinoLibs(self):
52 return []
53
54 def generateGlobalCode(self):
55 return ''
56
22 def generateSetupCode(self): 57 def generateSetupCode(self):
23 return '' 58 return ''
24 59
25 def generatePollCode(self): 60 def generatePollCode(self):
61 """if this returns nothing, we don't try to poll this device"""
26 return '' 62 return ''
27 63
28 def pinNumber(self, pred=ROOM['pin']): 64 def generateActionCode(self):
29 pinUri = self.graph.value(self.uri, pred) 65 """
30 return int(self.graph.value(pinUri, ROOM['pinNumber'])) 66 if you get called to do your action, this code reads the args you
67 need and do the right action
68 """
69 return ''
70
71 _knownTypes = set()
72 def register(deviceType):
73 _knownTypes.add(deviceType)
74 return deviceType
31 75
32 _inputForType = {} 76 @register
33 def registerInput(deviceType): 77 class PingInput(DeviceType):
34 def newcls(cls): 78 @classmethod
35 _inputForType[deviceType] = cls 79 def findInstances(cls, graph, board):
36 return cls 80 return [cls(graph, board, None)]
37 return newcls 81
38
39 class PingInput(BoardInput):
40 def generatePollCode(self): 82 def generatePollCode(self):
41 return "Serial.write('k');" 83 return "Serial.write('k');"
42 def readFromPoll(self, read): 84 def readFromPoll(self, read):
43 if read(1) != 'k': 85 if read(1) != 'k':
44 raise ValueError('invalid ping response') 86 raise ValueError('invalid ping response')
45 return [(self.uri, ROOM['ping'], ROOM['ok'])] 87 return [(self.uri, ROOM['ping'], ROOM['ok'])]
46 88
47 @registerInput(deviceType=ROOM['MotionSensor']) 89 @register
48 class MotionSensorInput(BoardInput): 90 class MotionSensorInput(DeviceType):
91 deviceType = ROOM['MotionSensor']
49 def generateSetupCode(self): 92 def generateSetupCode(self):
50 return 'pinMode(%(pin)d, INPUT); digitalWrite(%(pin)d, LOW);' % { 93 return 'pinMode(%(pin)d, INPUT); digitalWrite(%(pin)d, LOW);' % {
51 'pin': self.pinNumber(), 94 'pin': self.pinNumber(),
52 } 95 }
53 96
62 raise ValueError('unexpected response %r' % b) 105 raise ValueError('unexpected response %r' % b)
63 motion = b == 'y' 106 motion = b == 'y'
64 return [(self.uri, ROOM['sees'], 107 return [(self.uri, ROOM['sees'],
65 ROOM['motion'] if motion else ROOM['noMotion'])] 108 ROOM['motion'] if motion else ROOM['noMotion'])]
66 109
67 def makeBoardInput(graph, uri): 110 @register
68 deviceType = graph.value(uri, RDF.type) 111 class OneWire(DeviceType):
69 return _inputForType[deviceType](graph, uri) 112 deviceType = ROOM['OneWire']
113
114 def generateIncludes(self):
115 return ['OneWire.h', 'DallasTemperature.h']
116
117 def generateArduinoLibs(self):
118 return ['OneWire', 'DallasTemperature']
70 119
120 def generateGlobalCode(self):
121 # not yet isolated to support multiple OW buses
122 return '''
123 OneWire oneWire(%(pinNumber)s);
124 DallasTemperature sensors(&oneWire);
125 DeviceAddress tempSensorAddress;
126 #define NUM_TEMPERATURE_RETRIES 5
127
128 void initSensors() {
129 sensors.begin();
130 sensors.getAddress(tempSensorAddress, 0);
131 sensors.setResolution(tempSensorAddress, 12);
132 }
133
134 ''' % dict(pinNumber=self.pinNumber)
135 def generatePollCode(self):
136 return r'''
137 for (int i=0; i<NUM_TEMPERATURE_RETRIES; i++) {
138 sensors.requestTemperatures();
139 float newTemp = sensors.getTempF(tempSensorAddress);
140 if (i < NUM_TEMPERATURE_RETRIES-1 &&
141 (newTemp < -100 || newTemp > 180)) {
142 // too many errors that were fixed by restarting arduino.
143 // trying repeating this much init
144 initSensors();
145 continue;
146 }
147 Serial.print(newTemp);
148 Serial.print('\n');
149 Serial.print((char)i);
150 break;
151 }
152 '''
153
154 def readFromPoll(self, read):
155 newTemp = readLine(read)
156 retries = ord(read(1))
157 return [
158 (self.uri, ROOM['temperatureF'], Literal(newTemp)),
159 (self.uri, ROOM['temperatureRetries'], Literal(retries)),
160 ]
161
162 def makeDevices(graph, board):
163 out = []
164 for dt in sorted(_knownTypes, key=lambda cls: cls.__name__):
165 out.extend(dt.findInstances(graph, board))
166 return out
167