Mercurial > code > home > repos > homeauto
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 |