comparison service/arduinoNode/devices.py @ 170:376599552a4c

polymer board debug page with working output widgets Ignore-this: 3157d0c47a91afe47b30a5f182629d93
author drewp@bigasterisk.com
date Mon, 13 Apr 2015 23:30:12 -0700
parents d228105749ac
children 715c1c42185e
comparison
equal deleted inserted replaced
169:d228105749ac 170:376599552a4c
34 34
35 # subclasses may add args to this 35 # subclasses may add args to this
36 def __init__(self, graph, uri, pinNumber): 36 def __init__(self, graph, uri, pinNumber):
37 self.graph, self.uri = graph, uri 37 self.graph, self.uri = graph, uri
38 self.pinNumber = pinNumber 38 self.pinNumber = pinNumber
39
40 def description(self):
41 return {
42 'uri': self.uri,
43 'className': self.__class__.__name__,
44 'pinNumber': self.pinNumber,
45 'outputPatterns': self.outputPatterns(),
46 'watchPrefixes': self.watchPrefixes(),
47 'outputWidgets': self.outputWidgets(),
48 }
39 49
40 def readFromPoll(self, read): 50 def readFromPoll(self, read):
41 """ 51 """
42 read an update message returned as part of a poll bundle. This may 52 read an update message returned as part of a poll bundle. This may
43 consume a varying number of bytes depending on the type of 53 consume a varying number of bytes depending on the type of
44 input (e.g. IR receiver). 54 input (e.g. IR receiver).
45 Returns rdf statements. 55 Returns rdf statements.
46 """ 56 """
47 raise NotImplementedError('readFromPoll in %s' % self.__class__) 57 raise NotImplementedError('readFromPoll in %s' % self.__class__)
48 58
59 def watchPrefixes(self):
60 """
61 subj,pred pairs of the statements that might be returned from
62 readFromPoll, so the dashboard knows what it should
63 watch. This should be eliminated, as the dashboard should just
64 always watch the whole tree of statements starting self.uri
65 """
66 return []
67
49 def generateIncludes(self): 68 def generateIncludes(self):
69 """filenames of .h files to #include"""
50 return [] 70 return []
51 71
52 def generateArduinoLibs(self): 72 def generateArduinoLibs(self):
73 """names of libraries for the ARDUINO_LIBS line in the makefile"""
53 return [] 74 return []
54 75
55 def generateGlobalCode(self): 76 def generateGlobalCode(self):
77 """C code to emit in the global section"""
56 return '' 78 return ''
57 79
58 def generateSetupCode(self): 80 def generateSetupCode(self):
81 """C code to emit in setup()"""
59 return '' 82 return ''
60 83
61 def generatePollCode(self): 84 def generatePollCode(self):
62 """if this returns nothing, we don't try to poll this device""" 85 """
86 C code to run a poll update. This should Serial.write its output
87 for readFromPoll to consume. If this returns nothing, we don't
88 try to poll this device.
89 """
63 return '' 90 return ''
64 91
65 def generateActionCode(self): 92 def generateActionCode(self):
66 """ 93 """
67 If the host side runs sendOutput, this C code will be run on the 94 If the host side runs sendOutput, this C code will be run on the
76 Triple patterns, using None as a wildcard, that should be routed 103 Triple patterns, using None as a wildcard, that should be routed
77 to sendOutput 104 to sendOutput
78 """ 105 """
79 return [] 106 return []
80 107
108 def outputWidgets(self):
109 """
110 structs to make output widgets on the dashboard. ~1 of these per
111 handler you have in sendOutput
112 """
113 return []
114
81 def sendOutput(self, statements, write, read): 115 def sendOutput(self, statements, write, read):
82 """ 116 """
83 If we got statements that match this class's outputPatterns, this 117 If we got statements that match this class's outputPatterns, this
84 will be called with the statements that matched, and a serial 118 will be called with the statements that matched, and a serial
85 write method. What you write here will be available as 119 write method. What you write here will be available as
101 def findInstances(cls, graph, board): 135 def findInstances(cls, graph, board):
102 return [cls(graph, board, None)] 136 return [cls(graph, board, None)]
103 137
104 def generatePollCode(self): 138 def generatePollCode(self):
105 return "Serial.write('k');" 139 return "Serial.write('k');"
140
106 def readFromPoll(self, read): 141 def readFromPoll(self, read):
107 if read(1) != 'k': 142 if read(1) != 'k':
108 raise ValueError('invalid ping response') 143 raise ValueError('invalid ping response')
109 return [(self.uri, ROOM['ping'], ROOM['ok'])] 144 return [(self.uri, ROOM['ping'], ROOM['ok'])]
145
146 def watchPrefixes(self):
147 return [(self.uri, ROOM['ping'])]
110 148
111 @register 149 @register
112 class MotionSensorInput(DeviceType): 150 class MotionSensorInput(DeviceType):
113 deviceType = ROOM['MotionSensor'] 151 deviceType = ROOM['MotionSensor']
114 def generateSetupCode(self): 152 def generateSetupCode(self):
127 raise ValueError('unexpected response %r' % b) 165 raise ValueError('unexpected response %r' % b)
128 motion = b == 'y' 166 motion = b == 'y'
129 return [(self.uri, ROOM['sees'], 167 return [(self.uri, ROOM['sees'],
130 ROOM['motion'] if motion else ROOM['noMotion'])] 168 ROOM['motion'] if motion else ROOM['noMotion'])]
131 169
170 def watchPrefixes(self):
171 return [(self.uri, ROOM['sees'])]
172
132 @register 173 @register
133 class OneWire(DeviceType): 174 class OneWire(DeviceType):
175 """
176 A OW bus with temperature sensors (and maybe other devices, which
177 are also to be handled under this object)
178 """
134 deviceType = ROOM['OneWire'] 179 deviceType = ROOM['OneWire']
135 180
136 def generateIncludes(self): 181 def generateIncludes(self):
137 return ['OneWire.h', 'DallasTemperature.h'] 182 return ['OneWire.h', 'DallasTemperature.h']
138 183
174 ''' 219 '''
175 220
176 def readFromPoll(self, read): 221 def readFromPoll(self, read):
177 newTemp = readLine(read) 222 newTemp = readLine(read)
178 retries = ord(read(1)) 223 retries = ord(read(1))
224 # uri will change; there could (likely) be multiple connected sensors
179 return [ 225 return [
180 (self.uri, ROOM['temperatureF'], 226 (self.uri, ROOM['temperatureF'],
181 Literal(newTemp, datatype=XSD['decimal'])), 227 Literal(newTemp, datatype=XSD['decimal'])),
182 (self.uri, ROOM['temperatureRetries'], Literal(retries)), 228 (self.uri, ROOM['temperatureRetries'], Literal(retries)),
183 ] 229 ]
230
231 def watchPrefixes(self):
232 # these uris will become dynamic! see note on watchPrefixes
233 # about eliminating it.
234 return [(self.uri, ROOM['temperatureF']),
235 (self.uri, ROOM['temperatureRetries']),
236 ]
184 237
185 def byteFromFloat(f): 238 def byteFromFloat(f):
186 return chr(int(min(255, max(0, f * 255)))) 239 return chr(int(min(255, max(0, f * 255))))
187 240
188 @register 241 @register
207 def generateActionCode(self): 260 def generateActionCode(self):
208 return r''' 261 return r'''
209 while(Serial.available() < 1) NULL; 262 while(Serial.available() < 1) NULL;
210 analogWrite(%(pin)d, Serial.read()); 263 analogWrite(%(pin)d, Serial.read());
211 ''' % dict(pin=self.pinNumber) 264 ''' % dict(pin=self.pinNumber)
265
266 def outputWidgets(self):
267 return [{
268 'element': 'output-slider',
269 'min': 0,
270 'max': 1,
271 'step': 1 / 255,
272 'subj': self.uri,
273 'pred': ROOM['brightness'],
274 }]
275
276 @register
277 class DigitalOutput(DeviceType):
278 deviceType = ROOM['DigitalOutput']
279 def generateSetupCode(self):
280 return 'pinMode(%(pin)d, OUTPUT); digitalWrite(%(pin)d, LOW);' % {
281 'pin': self.pinNumber,
282 }
283
284 def outputPatterns(self):
285 return [(self.uri, ROOM['level'], None)]
286
287 def sendOutput(self, statements, write, read):
288 assert len(statements) == 1
289 assert statements[0][:2] == (self.uri, ROOM['level'])
290 value = {"high": 1, "low": 0}[str(statements[0][2])]
291 write(chr(value))
292
293 def generateActionCode(self):
294 return r'''
295 while(Serial.available() < 1) NULL;
296 digitalWrite(%(pin)d, Serial.read());
297 ''' % dict(pin=self.pinNumber)
298
299 def outputWidgets(self):
300 return [{
301 'element': 'output-switch',
302 'subj': self.uri,
303 'pred': ROOM['level'],
304 }]
212 305
213 @register 306 @register
214 class ST7576Lcd(DeviceType): 307 class ST7576Lcd(DeviceType):
215 deviceType = ROOM['ST7565Lcd'] 308 deviceType = ROOM['ST7565Lcd']
216 @classmethod 309 @classmethod
271 assert statements[0][:2] == (self.uri, ROOM['text']) 364 assert statements[0][:2] == (self.uri, ROOM['text'])
272 value = str(statements[0][2]) 365 value = str(statements[0][2])
273 assert len(value) < 254, repr(value) 366 assert len(value) < 254, repr(value)
274 write(chr(len(value)) + value) 367 write(chr(len(value)) + value)
275 368
369 def outputWidgets(self):
370 return [{
371 'element': 'output-fixed-text',
372 'cols': 21,
373 'rows': 8,
374 'subj': self.uri,
375 'pred': ROOM['text'],
376 }]
377
276 def generateActionCode(self): 378 def generateActionCode(self):
277 return ''' 379 return '''
278 while(Serial.available() < 1) NULL; 380 while(Serial.available() < 1) NULL;
279 byte bufSize = Serial.read(); 381 byte bufSize = Serial.read();
280 for (byte i = 0; i < bufSize; i++) { 382 for (byte i = 0; i < bufSize; ++i) {
281 while(Serial.available() < 1) NULL; 383 while(Serial.available() < 1) NULL;
282 newtxt[i] = Serial.read(); 384 newtxt[i] = Serial.read();
385 }
386 for (byte i = bufSize; i < sizeof(newtxt); ++i) {
387 newtxt[i] = 0;
283 } 388 }
284 glcd.clear(); 389 glcd.clear();
285 glcd.drawstring(0,0, newtxt); 390 glcd.drawstring(0,0, newtxt);
286 glcd.display(); 391 glcd.display();
287 ''' 392 '''