Mercurial > code > home > repos > homeauto
comparison service/arduinoNode/devices.py @ 974:f707210c13bd
new /output to post statements which devices can handle. led and lcd output working
Ignore-this: afa16b081869a52380b04271a35c53c7
darcs-hash:20150412104414-312f9-f0e67d9f939025fd0a67e78463e6902ddcf0e6d9
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sun, 12 Apr 2015 03:44:14 -0700 |
parents | fbe72d44f15a |
children | 376599552a4c |
comparison
equal
deleted
inserted
replaced
973:d7e8227fefc5 | 974:f707210c13bd |
---|---|
1 from __future__ import division | |
2 import itertools | |
1 from rdflib import Namespace, RDF, URIRef, Literal | 3 from rdflib import Namespace, RDF, URIRef, Literal |
2 | 4 |
3 ROOM = Namespace('http://projects.bigasterisk.com/room/') | 5 ROOM = Namespace('http://projects.bigasterisk.com/room/') |
6 XSD = Namespace('http://www.w3.org/2001/XMLSchema#') | |
4 | 7 |
5 def readLine(read): | 8 def readLine(read): |
6 buf = '' | 9 buf = '' |
7 for c in iter(lambda: read(1), '\n'): | 10 for c in iter(lambda: read(1), '\n'): |
8 buf += c | 11 buf += c |
16 return any number of instances of this class for all the separately | 19 return any number of instances of this class for all the separately |
17 controlled devices on the board. Two LEDS makes two instances, | 20 controlled devices on the board. Two LEDS makes two instances, |
18 but two sensors on the same onewire bus makes only one device | 21 but two sensors on the same onewire bus makes only one device |
19 (which yields more statements). | 22 (which yields more statements). |
20 """ | 23 """ |
21 instances = [] | |
22 for row in graph.query("""SELECT ?dev ?pinNumber WHERE { | 24 for row in graph.query("""SELECT ?dev ?pinNumber WHERE { |
23 ?board :hasPin ?pin . | 25 ?board :hasPin ?pin . |
24 ?pin :pinNumber ?pinNumber; | 26 ?pin :pinNumber ?pinNumber; |
25 :connectedTo ?dev . | 27 :connectedTo ?dev . |
26 ?dev a ?thisType . | 28 ?dev a ?thisType . |
27 } ORDER BY ?dev""", | 29 } ORDER BY ?dev""", |
28 initBindings=dict(board=board, | 30 initBindings=dict(board=board, |
29 thisType=cls.deviceType), | 31 thisType=cls.deviceType), |
30 initNs={'': ROOM}): | 32 initNs={'': ROOM}): |
31 instances.append(cls(graph, row.dev, int(row.pinNumber))) | 33 yield cls(graph, row.dev, int(row.pinNumber)) |
32 return instances | |
33 | 34 |
34 # subclasses may add args to this | 35 # subclasses may add args to this |
35 def __init__(self, graph, uri, pinNumber): | 36 def __init__(self, graph, uri, pinNumber): |
36 self.graph, self.uri = graph, uri | 37 self.graph, self.uri = graph, uri |
37 self.pinNumber = pinNumber | 38 self.pinNumber = pinNumber |
61 """if this returns nothing, we don't try to poll this device""" | 62 """if this returns nothing, we don't try to poll this device""" |
62 return '' | 63 return '' |
63 | 64 |
64 def generateActionCode(self): | 65 def generateActionCode(self): |
65 """ | 66 """ |
66 if you get called to do your action, this code reads the args you | 67 If the host side runs sendOutput, this C code will be run on the |
67 need and do the right action | 68 board to receive whatever sendOutput writes. Each sendOutput |
69 write(buf) call should be matched with len(buf) Serial.read() | |
70 calls in here. | |
68 """ | 71 """ |
69 return '' | 72 return '' |
70 | 73 |
74 def outputPatterns(self): | |
75 """ | |
76 Triple patterns, using None as a wildcard, that should be routed | |
77 to sendOutput | |
78 """ | |
79 return [] | |
80 | |
81 def sendOutput(self, statements, write, read): | |
82 """ | |
83 If we got statements that match this class's outputPatterns, this | |
84 will be called with the statements that matched, and a serial | |
85 write method. What you write here will be available as | |
86 Serial.read in the generateActionCode C code. | |
87 | |
88 Todo: it would be fine to read back confirmations or | |
89 whatever. Just need a way to collect them into graph statements. | |
90 """ | |
91 raise NotImplementedError | |
92 | |
71 _knownTypes = set() | 93 _knownTypes = set() |
72 def register(deviceType): | 94 def register(deviceType): |
73 _knownTypes.add(deviceType) | 95 _knownTypes.add(deviceType) |
74 return deviceType | 96 return deviceType |
75 | 97 |
89 @register | 111 @register |
90 class MotionSensorInput(DeviceType): | 112 class MotionSensorInput(DeviceType): |
91 deviceType = ROOM['MotionSensor'] | 113 deviceType = ROOM['MotionSensor'] |
92 def generateSetupCode(self): | 114 def generateSetupCode(self): |
93 return 'pinMode(%(pin)d, INPUT); digitalWrite(%(pin)d, LOW);' % { | 115 return 'pinMode(%(pin)d, INPUT); digitalWrite(%(pin)d, LOW);' % { |
94 'pin': self.pinNumber(), | 116 'pin': self.pinNumber, |
95 } | 117 } |
96 | 118 |
97 def generatePollCode(self): | 119 def generatePollCode(self): |
98 return "Serial.write(digitalRead(%(pin)d) ? 'y' : 'n');" % { | 120 return "Serial.write(digitalRead(%(pin)d) ? 'y' : 'n');" % { |
99 'pin': self.pinNumber() | 121 'pin': self.pinNumber |
100 } | 122 } |
101 | 123 |
102 def readFromPoll(self, read): | 124 def readFromPoll(self, read): |
103 b = read(1) | 125 b = read(1) |
104 if b not in 'yn': | 126 if b not in 'yn': |
121 # not yet isolated to support multiple OW buses | 143 # not yet isolated to support multiple OW buses |
122 return ''' | 144 return ''' |
123 OneWire oneWire(%(pinNumber)s); | 145 OneWire oneWire(%(pinNumber)s); |
124 DallasTemperature sensors(&oneWire); | 146 DallasTemperature sensors(&oneWire); |
125 DeviceAddress tempSensorAddress; | 147 DeviceAddress tempSensorAddress; |
126 #define NUM_TEMPERATURE_RETRIES 5 | 148 #define NUM_TEMPERATURE_RETRIES 2 |
127 | 149 |
128 void initSensors() { | 150 void initSensors() { |
129 sensors.begin(); | 151 sensors.begin(); |
130 sensors.getAddress(tempSensorAddress, 0); | 152 sensors.getAddress(tempSensorAddress, 0); |
131 sensors.setResolution(tempSensorAddress, 12); | 153 sensors.setResolution(tempSensorAddress, 12); |
132 } | 154 } |
133 | |
134 ''' % dict(pinNumber=self.pinNumber) | 155 ''' % dict(pinNumber=self.pinNumber) |
156 | |
135 def generatePollCode(self): | 157 def generatePollCode(self): |
136 return r''' | 158 return r''' |
137 for (int i=0; i<NUM_TEMPERATURE_RETRIES; i++) { | 159 for (int i=0; i<NUM_TEMPERATURE_RETRIES; i++) { |
138 sensors.requestTemperatures(); | 160 sensors.requestTemperatures(); |
139 float newTemp = sensors.getTempF(tempSensorAddress); | 161 float newTemp = sensors.getTempF(tempSensorAddress); |
153 | 175 |
154 def readFromPoll(self, read): | 176 def readFromPoll(self, read): |
155 newTemp = readLine(read) | 177 newTemp = readLine(read) |
156 retries = ord(read(1)) | 178 retries = ord(read(1)) |
157 return [ | 179 return [ |
158 (self.uri, ROOM['temperatureF'], Literal(newTemp)), | 180 (self.uri, ROOM['temperatureF'], |
181 Literal(newTemp, datatype=XSD['decimal'])), | |
159 (self.uri, ROOM['temperatureRetries'], Literal(retries)), | 182 (self.uri, ROOM['temperatureRetries'], Literal(retries)), |
160 ] | 183 ] |
184 | |
185 def byteFromFloat(f): | |
186 return chr(int(min(255, max(0, f * 255)))) | |
187 | |
188 @register | |
189 class LedOutput(DeviceType): | |
190 deviceType = ROOM['LedOutput'] | |
191 def generateSetupCode(self): | |
192 return 'pinMode(%(pin)d, OUTPUT); digitalWrite(%(pin)d, LOW);' % { | |
193 'pin': self.pinNumber, | |
194 } | |
195 | |
196 def outputPatterns(self): | |
197 return [(self.uri, ROOM['brightness'], None)] | |
198 | |
199 def sendOutput(self, statements, write, read): | |
200 assert len(statements) == 1 | |
201 assert statements[0][:2] == (self.uri, ROOM['brightness']) | |
202 value = float(statements[0][2]) | |
203 if (self.uri, RDF.type, ROOM['ActiveLowOutput']): | |
204 value = 1 - value | |
205 write(byteFromFloat(value)) | |
206 | |
207 def generateActionCode(self): | |
208 return r''' | |
209 while(Serial.available() < 1) NULL; | |
210 analogWrite(%(pin)d, Serial.read()); | |
211 ''' % dict(pin=self.pinNumber) | |
212 | |
213 @register | |
214 class ST7576Lcd(DeviceType): | |
215 deviceType = ROOM['ST7565Lcd'] | |
216 @classmethod | |
217 def findInstances(cls, graph, board): | |
218 grouped = itertools.groupby( | |
219 graph.query("""SELECT DISTINCT ?dev ?pred ?pinNumber WHERE { | |
220 ?board :hasPin ?pin . | |
221 ?pin :pinNumber ?pinNumber; | |
222 :connectedTo ?devPin . | |
223 ?dev a :ST7565Lcd . | |
224 ?dev ?pred ?devPin . | |
225 } ORDER BY ?dev""", | |
226 initBindings=dict(board=board, | |
227 thisType=cls.deviceType), | |
228 initNs={'': ROOM}), | |
229 lambda row: row.dev) | |
230 for dev, connections in grouped: | |
231 connections = dict((role, int(num)) for unused_dev, role, num | |
232 in connections) | |
233 yield cls(graph, dev, connections=connections) | |
234 | |
235 def __init__(self, graph, dev, connections): | |
236 super(ST7576Lcd, self).__init__(graph, dev, pinNumber=None) | |
237 self.connections = connections | |
238 | |
239 def generateIncludes(self): | |
240 return ['ST7565.h'] | |
241 | |
242 def generateArduinoLibs(self): | |
243 return ['ST7565'] | |
244 | |
245 def generateGlobalCode(self): | |
246 return ''' | |
247 ST7565 glcd(%(SID)d, %(SCLK)d, %(A0)d, %(RST)d, %(CS)d); | |
248 char newtxt[21*8+1]; | |
249 unsigned int written; | |
250 ''' % dict(SID=self.connections[ROOM['lcdSID']], | |
251 SCLK=self.connections[ROOM['lcdSCLK']], | |
252 A0=self.connections[ROOM['lcdA0']], | |
253 RST=self.connections[ROOM['lcdRST']], | |
254 CS=self.connections[ROOM['lcdCS']]) | |
255 | |
256 def generateSetupCode(self): | |
257 return ''' | |
258 glcd.st7565_init(); | |
259 glcd.st7565_command(CMD_DISPLAY_ON); | |
260 glcd.st7565_command(CMD_SET_ALLPTS_NORMAL); | |
261 glcd.st7565_set_brightness(0x18); | |
262 | |
263 glcd.display(); // show splashscreen | |
264 ''' | |
265 | |
266 def outputPatterns(self): | |
267 return [(self.uri, ROOM['text'], None)] | |
268 | |
269 def sendOutput(self, statements, write, read): | |
270 assert len(statements) == 1 | |
271 assert statements[0][:2] == (self.uri, ROOM['text']) | |
272 value = str(statements[0][2]) | |
273 assert len(value) < 254, repr(value) | |
274 write(chr(len(value)) + value) | |
275 | |
276 def generateActionCode(self): | |
277 return ''' | |
278 while(Serial.available() < 1) NULL; | |
279 byte bufSize = Serial.read(); | |
280 for (byte i = 0; i < bufSize; i++) { | |
281 while(Serial.available() < 1) NULL; | |
282 newtxt[i] = Serial.read(); | |
283 } | |
284 glcd.clear(); | |
285 glcd.drawstring(0,0, newtxt); | |
286 glcd.display(); | |
287 ''' | |
161 | 288 |
162 def makeDevices(graph, board): | 289 def makeDevices(graph, board): |
163 out = [] | 290 out = [] |
164 for dt in sorted(_knownTypes, key=lambda cls: cls.__name__): | 291 for dt in sorted(_knownTypes, key=lambda cls: cls.__name__): |
165 out.extend(dt.findInstances(graph, board)) | 292 out.extend(dt.findInstances(graph, board)) |