Mercurial > code > home > repos > homeauto
diff 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 |
line wrap: on
line diff
--- a/service/arduinoNode/devices.py Sun Apr 12 03:43:20 2015 -0700 +++ b/service/arduinoNode/devices.py Sun Apr 12 03:44:14 2015 -0700 @@ -1,6 +1,9 @@ +from __future__ import division +import itertools from rdflib import Namespace, RDF, URIRef, Literal ROOM = Namespace('http://projects.bigasterisk.com/room/') +XSD = Namespace('http://www.w3.org/2001/XMLSchema#') def readLine(read): buf = '' @@ -18,7 +21,6 @@ but two sensors on the same onewire bus makes only one device (which yields more statements). """ - instances = [] for row in graph.query("""SELECT ?dev ?pinNumber WHERE { ?board :hasPin ?pin . ?pin :pinNumber ?pinNumber; @@ -28,8 +30,7 @@ initBindings=dict(board=board, thisType=cls.deviceType), initNs={'': ROOM}): - instances.append(cls(graph, row.dev, int(row.pinNumber))) - return instances + yield cls(graph, row.dev, int(row.pinNumber)) # subclasses may add args to this def __init__(self, graph, uri, pinNumber): @@ -63,11 +64,32 @@ def generateActionCode(self): """ - if you get called to do your action, this code reads the args you - need and do the right action + If the host side runs sendOutput, this C code will be run on the + board to receive whatever sendOutput writes. Each sendOutput + write(buf) call should be matched with len(buf) Serial.read() + calls in here. """ return '' + def outputPatterns(self): + """ + Triple patterns, using None as a wildcard, that should be routed + to sendOutput + """ + return [] + + def sendOutput(self, statements, write, read): + """ + If we got statements that match this class's outputPatterns, this + will be called with the statements that matched, and a serial + write method. What you write here will be available as + Serial.read in the generateActionCode C code. + + Todo: it would be fine to read back confirmations or + whatever. Just need a way to collect them into graph statements. + """ + raise NotImplementedError + _knownTypes = set() def register(deviceType): _knownTypes.add(deviceType) @@ -91,12 +113,12 @@ deviceType = ROOM['MotionSensor'] def generateSetupCode(self): return 'pinMode(%(pin)d, INPUT); digitalWrite(%(pin)d, LOW);' % { - 'pin': self.pinNumber(), + 'pin': self.pinNumber, } def generatePollCode(self): return "Serial.write(digitalRead(%(pin)d) ? 'y' : 'n');" % { - 'pin': self.pinNumber() + 'pin': self.pinNumber } def readFromPoll(self, read): @@ -123,15 +145,15 @@ OneWire oneWire(%(pinNumber)s); DallasTemperature sensors(&oneWire); DeviceAddress tempSensorAddress; -#define NUM_TEMPERATURE_RETRIES 5 +#define NUM_TEMPERATURE_RETRIES 2 void initSensors() { sensors.begin(); sensors.getAddress(tempSensorAddress, 0); sensors.setResolution(tempSensorAddress, 12); } + ''' % dict(pinNumber=self.pinNumber) - ''' % dict(pinNumber=self.pinNumber) def generatePollCode(self): return r''' for (int i=0; i<NUM_TEMPERATURE_RETRIES; i++) { @@ -155,10 +177,115 @@ newTemp = readLine(read) retries = ord(read(1)) return [ - (self.uri, ROOM['temperatureF'], Literal(newTemp)), + (self.uri, ROOM['temperatureF'], + Literal(newTemp, datatype=XSD['decimal'])), (self.uri, ROOM['temperatureRetries'], Literal(retries)), ] +def byteFromFloat(f): + return chr(int(min(255, max(0, f * 255)))) + +@register +class LedOutput(DeviceType): + deviceType = ROOM['LedOutput'] + def generateSetupCode(self): + return 'pinMode(%(pin)d, OUTPUT); digitalWrite(%(pin)d, LOW);' % { + 'pin': self.pinNumber, + } + + def outputPatterns(self): + return [(self.uri, ROOM['brightness'], None)] + + def sendOutput(self, statements, write, read): + assert len(statements) == 1 + assert statements[0][:2] == (self.uri, ROOM['brightness']) + value = float(statements[0][2]) + if (self.uri, RDF.type, ROOM['ActiveLowOutput']): + value = 1 - value + write(byteFromFloat(value)) + + def generateActionCode(self): + return r''' + while(Serial.available() < 1) NULL; + analogWrite(%(pin)d, Serial.read()); + ''' % dict(pin=self.pinNumber) + +@register +class ST7576Lcd(DeviceType): + deviceType = ROOM['ST7565Lcd'] + @classmethod + def findInstances(cls, graph, board): + grouped = itertools.groupby( + graph.query("""SELECT DISTINCT ?dev ?pred ?pinNumber WHERE { + ?board :hasPin ?pin . + ?pin :pinNumber ?pinNumber; + :connectedTo ?devPin . + ?dev a :ST7565Lcd . + ?dev ?pred ?devPin . + } ORDER BY ?dev""", + initBindings=dict(board=board, + thisType=cls.deviceType), + initNs={'': ROOM}), + lambda row: row.dev) + for dev, connections in grouped: + connections = dict((role, int(num)) for unused_dev, role, num + in connections) + yield cls(graph, dev, connections=connections) + + def __init__(self, graph, dev, connections): + super(ST7576Lcd, self).__init__(graph, dev, pinNumber=None) + self.connections = connections + + def generateIncludes(self): + return ['ST7565.h'] + + def generateArduinoLibs(self): + return ['ST7565'] + + def generateGlobalCode(self): + return ''' + ST7565 glcd(%(SID)d, %(SCLK)d, %(A0)d, %(RST)d, %(CS)d); + char newtxt[21*8+1]; + unsigned int written; + ''' % dict(SID=self.connections[ROOM['lcdSID']], + SCLK=self.connections[ROOM['lcdSCLK']], + A0=self.connections[ROOM['lcdA0']], + RST=self.connections[ROOM['lcdRST']], + CS=self.connections[ROOM['lcdCS']]) + + def generateSetupCode(self): + return ''' + glcd.st7565_init(); + glcd.st7565_command(CMD_DISPLAY_ON); + glcd.st7565_command(CMD_SET_ALLPTS_NORMAL); + glcd.st7565_set_brightness(0x18); + + glcd.display(); // show splashscreen + ''' + + def outputPatterns(self): + return [(self.uri, ROOM['text'], None)] + + def sendOutput(self, statements, write, read): + assert len(statements) == 1 + assert statements[0][:2] == (self.uri, ROOM['text']) + value = str(statements[0][2]) + assert len(value) < 254, repr(value) + write(chr(len(value)) + value) + + def generateActionCode(self): + return ''' + while(Serial.available() < 1) NULL; + byte bufSize = Serial.read(); + for (byte i = 0; i < bufSize; i++) { + while(Serial.available() < 1) NULL; + newtxt[i] = Serial.read(); + } + glcd.clear(); + glcd.drawstring(0,0, newtxt); + glcd.display(); + ''' + def makeDevices(graph, board): out = [] for dt in sorted(_knownTypes, key=lambda cls: cls.__name__):